fix: ignore reverse relations during tenant autofill
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# NetBox Utilities
|
||||
|
||||
Plugin für **NetBox 4.6.5 bis 4.6.7** mit zwölf Funktionen:
|
||||
Plugin für **NetBox 4.6.5 bis 4.6.8** mit zwölf Funktionen:
|
||||
|
||||
- Jeder Benutzer kann die Menüs der linken Navigation verschieben oder ausblenden.
|
||||
- Ein Dropdown in der Kopfleiste setzt einen sitzungsweiten Filter für einen Mandanten oder eine Mandantengruppe.
|
||||
@@ -17,6 +17,11 @@ Plugin für **NetBox 4.6.5 bis 4.6.7** mit zwölf Funktionen:
|
||||
|
||||
Die Navigationseinstellungen sind benutzerbezogen. Die aktive Mandanten- oder Gruppenauswahl wird in der jeweiligen Browser-Session gespeichert.
|
||||
|
||||
Ab Version `0.10.1` ignoriert die automatische Mandantenermittlung
|
||||
mehrwertige Reverse-Relationen. Das behebt unter NetBox 4.6.8 insbesondere den
|
||||
Fehler `'RelatedManager' object has no attribute '_meta'` beim Öffnen der
|
||||
Seite zum Anlegen einer VLAN-Gruppe.
|
||||
|
||||
## Kompatibilität
|
||||
|
||||
- NetBox `>=4.6.5,<4.7`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from netbox.plugins import PluginConfig, get_plugin_config
|
||||
|
||||
__version__ = "0.10.0"
|
||||
__version__ = "0.10.1"
|
||||
|
||||
|
||||
class NetBoxUtilitiesConfig(PluginConfig):
|
||||
|
||||
@@ -25,16 +25,20 @@ def tenant_id_from_object(obj, depth=0):
|
||||
if isinstance(obj, Tenant):
|
||||
return obj.pk
|
||||
|
||||
field_names = {field.name for field in obj._meta.get_fields()}
|
||||
if "tenant" in field_names and getattr(obj, "tenant_id", None):
|
||||
meta = getattr(obj, "_meta", None)
|
||||
if meta is None or not hasattr(meta, "get_fields"):
|
||||
return None
|
||||
fields = {field.name: field for field in meta.get_fields()}
|
||||
if "tenant" in fields and getattr(obj, "tenant_id", None):
|
||||
return obj.tenant_id
|
||||
|
||||
for relation in PARENT_RELATIONS:
|
||||
if relation not in field_names:
|
||||
field = fields.get(relation)
|
||||
if field is None or getattr(field, "one_to_many", False) or getattr(field, "many_to_many", False):
|
||||
continue
|
||||
try:
|
||||
parent = getattr(obj, relation, None)
|
||||
except (ObjectDoesNotExist, ValueError):
|
||||
except (AttributeError, ObjectDoesNotExist, ValueError):
|
||||
continue
|
||||
if tenant_id := tenant_id_from_object(parent, depth + 1):
|
||||
return tenant_id
|
||||
@@ -76,11 +80,7 @@ def _related_objects(form, field_name):
|
||||
|
||||
def _is_cable(instance):
|
||||
meta = getattr(instance, "_meta", None)
|
||||
return bool(
|
||||
meta
|
||||
and getattr(meta, "app_label", None) == "dcim"
|
||||
and getattr(meta, "model_name", None) == "cable"
|
||||
)
|
||||
return bool(meta and getattr(meta, "app_label", None) == "dcim" and getattr(meta, "model_name", None) == "cable")
|
||||
|
||||
|
||||
def _instance_cable_terminations(instance):
|
||||
|
||||
@@ -449,7 +449,7 @@ class ReorderRackFrontendTest(SimpleTestCase):
|
||||
self.assertEqual(template_name, "netbox_utilities/reorder_rack.html")
|
||||
self.assertEqual(context["reorder_devices"][0]["label"], "LEO-Fritzbox")
|
||||
self.assertEqual(context["reorder_devices"][0]["grid_width"], 6)
|
||||
self.assertEqual(context["asset_version"], "0.10.0")
|
||||
self.assertEqual(context["asset_version"], "0.10.1")
|
||||
self.assertIs(context["reorder_rack_width_data"], get_width_data.return_value)
|
||||
get_width_data.assert_called_once()
|
||||
self.assertIs(get_width_data.call_args.kwargs["rack"], rack)
|
||||
|
||||
@@ -50,6 +50,17 @@ class FakeQuerySet:
|
||||
|
||||
|
||||
class TenantAutofillTest(SimpleTestCase):
|
||||
def test_netbox_vlan_group_reverse_scopes_do_not_break_autofill(self):
|
||||
from ipam.models import VLANGroup
|
||||
|
||||
self.assertIsNone(tenant_id_from_object(VLANGroup()))
|
||||
|
||||
def test_ignores_reverse_relation_managers_on_scoped_objects(self):
|
||||
reverse_manager = SimpleNamespace()
|
||||
vlan_group = FakeObject(site=reverse_manager, rack=reverse_manager)
|
||||
|
||||
self.assertIsNone(tenant_id_from_object(vlan_group))
|
||||
|
||||
def test_finds_tenant_through_parent_relation(self):
|
||||
rack = FakeObject(tenant_id=42)
|
||||
device = FakeObject(rack=rack)
|
||||
|
||||
@@ -246,7 +246,7 @@ class TopologyViewsRackWidthTest(SimpleTestCase):
|
||||
self.assertIn('id="netbox-utilities-topology-rack-width-styles"', html)
|
||||
self.assertIn('.rack-device[href="/dcim/devices/334/"]', html)
|
||||
self.assertIn("left: calc(50% + 3px) !important", html)
|
||||
self.assertIn("netbox_utilities/topology-rack-width.js?v=0.10.0", html)
|
||||
self.assertIn("netbox_utilities/topology-rack-width.js?v=0.10.1", html)
|
||||
self.assertIn("left:calc(0% + 3px)!important", html)
|
||||
self.assertIn("left:calc(50% + 3px)!important", html)
|
||||
self.assertIn("width:calc(50% - 6px)!important", html)
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "netbox-utilities"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
description = "Navigation, tenant utilities, connection VLANs, partial-width racks, and bulk operations for NetBox 4.6"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
Reference in New Issue
Block a user