Skip to content

Commit 31cc0b7

Browse files
committed
Order virtual chassis panels by rack position
Stack members were iterated in device-name alphabetical order (Django's default Meta.ordering). Panels now render top-of-rack first, respecting the rack's desc_units flag: - desc_units=False (default, U1 at bottom): sort descending by U so the highest-numbered unit (top of rack) appears first. - desc_units=True (U1 at top): sort ascending by U so the lowest- numbered unit (top of rack) appears first. Members without a rack position are placed last, tiebroken by vc_position. Uses select_related('rack') to avoid N+1 queries.
1 parent 97e4e9f commit 31cc0b7

1 file changed

Lines changed: 34 additions & 2 deletions

File tree

netbox_device_view/utils.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,30 @@ def process_ports(ports, ports_chassis, dev):
171171
return ports_chassis
172172

173173

174+
def _rack_sort_key(member):
175+
"""Sort key for virtual chassis members by physical rack position.
176+
177+
Respects the rack's ``desc_units`` flag:
178+
- desc_units=False (default): U1 is at the bottom → higher U = higher in rack
179+
→ sort descending so the top-of-rack device appears first.
180+
- desc_units=True: U1 is at the top → lower U = higher in rack
181+
→ sort ascending so the top-of-rack device appears first.
182+
183+
Members without a rack position are placed last, tiebroken by vc_position.
184+
"""
185+
pos = member.position
186+
vc = member.vc_position if member.vc_position is not None else 0
187+
if pos is None:
188+
return (1, float("inf"), vc) # un-racked: always last
189+
desc = bool(member.rack and member.rack.desc_units)
190+
if desc:
191+
# U1 at top → ascending: smallest U first
192+
return (0, float(pos), vc)
193+
else:
194+
# U1 at bottom → descending: largest U first (negate)
195+
return (0, -float(pos), vc)
196+
197+
174198
def prepare(obj):
175199
"""Return (dv, modules, ports_chassis, device_view) for the given device.
176200
@@ -198,7 +222,11 @@ def prepare(obj):
198222
obj.name,
199223
)
200224
else:
201-
for member in obj.virtual_chassis.members.all():
225+
members = sorted(
226+
obj.virtual_chassis.members.select_related("rack").all(),
227+
key=_rack_sort_key,
228+
)
229+
for member in members:
202230
pos = member.vc_position
203231
member_view = DeviceView.objects.get(device_type=member.device_type)
204232
member_css = get_css_for_device_view(member_view)
@@ -256,7 +284,11 @@ def prepare_svg(obj):
256284
obj.name,
257285
)
258286
else:
259-
for member in obj.virtual_chassis.members.all():
287+
members = sorted(
288+
obj.virtual_chassis.members.select_related("rack").all(),
289+
key=_rack_sort_key,
290+
)
291+
for member in members:
260292
pos = member.vc_position
261293
member_view = DeviceView.objects.get(device_type=member.device_type)
262294
member_modules = list(member.modules.all())

0 commit comments

Comments
 (0)