fix: ignore reverse relations during tenant autofill
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# NetBox Utilities
|
# 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.
|
- 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.
|
- 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.
|
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
|
## Kompatibilität
|
||||||
|
|
||||||
- NetBox `>=4.6.5,<4.7`
|
- NetBox `>=4.6.5,<4.7`
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from netbox.plugins import PluginConfig, get_plugin_config
|
from netbox.plugins import PluginConfig, get_plugin_config
|
||||||
|
|
||||||
__version__ = "0.10.0"
|
__version__ = "0.10.1"
|
||||||
|
|
||||||
|
|
||||||
class NetBoxUtilitiesConfig(PluginConfig):
|
class NetBoxUtilitiesConfig(PluginConfig):
|
||||||
|
|||||||
@@ -25,16 +25,20 @@ def tenant_id_from_object(obj, depth=0):
|
|||||||
if isinstance(obj, Tenant):
|
if isinstance(obj, Tenant):
|
||||||
return obj.pk
|
return obj.pk
|
||||||
|
|
||||||
field_names = {field.name for field in obj._meta.get_fields()}
|
meta = getattr(obj, "_meta", None)
|
||||||
if "tenant" in field_names and getattr(obj, "tenant_id", 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
|
return obj.tenant_id
|
||||||
|
|
||||||
for relation in PARENT_RELATIONS:
|
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
|
continue
|
||||||
try:
|
try:
|
||||||
parent = getattr(obj, relation, None)
|
parent = getattr(obj, relation, None)
|
||||||
except (ObjectDoesNotExist, ValueError):
|
except (AttributeError, ObjectDoesNotExist, ValueError):
|
||||||
continue
|
continue
|
||||||
if tenant_id := tenant_id_from_object(parent, depth + 1):
|
if tenant_id := tenant_id_from_object(parent, depth + 1):
|
||||||
return tenant_id
|
return tenant_id
|
||||||
@@ -76,11 +80,7 @@ def _related_objects(form, field_name):
|
|||||||
|
|
||||||
def _is_cable(instance):
|
def _is_cable(instance):
|
||||||
meta = getattr(instance, "_meta", None)
|
meta = getattr(instance, "_meta", None)
|
||||||
return bool(
|
return bool(meta and getattr(meta, "app_label", None) == "dcim" and getattr(meta, "model_name", None) == "cable")
|
||||||
meta
|
|
||||||
and getattr(meta, "app_label", None) == "dcim"
|
|
||||||
and getattr(meta, "model_name", None) == "cable"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _instance_cable_terminations(instance):
|
def _instance_cable_terminations(instance):
|
||||||
|
|||||||
@@ -449,7 +449,7 @@ class ReorderRackFrontendTest(SimpleTestCase):
|
|||||||
self.assertEqual(template_name, "netbox_utilities/reorder_rack.html")
|
self.assertEqual(template_name, "netbox_utilities/reorder_rack.html")
|
||||||
self.assertEqual(context["reorder_devices"][0]["label"], "LEO-Fritzbox")
|
self.assertEqual(context["reorder_devices"][0]["label"], "LEO-Fritzbox")
|
||||||
self.assertEqual(context["reorder_devices"][0]["grid_width"], 6)
|
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)
|
self.assertIs(context["reorder_rack_width_data"], get_width_data.return_value)
|
||||||
get_width_data.assert_called_once()
|
get_width_data.assert_called_once()
|
||||||
self.assertIs(get_width_data.call_args.kwargs["rack"], rack)
|
self.assertIs(get_width_data.call_args.kwargs["rack"], rack)
|
||||||
|
|||||||
@@ -50,6 +50,17 @@ class FakeQuerySet:
|
|||||||
|
|
||||||
|
|
||||||
class TenantAutofillTest(SimpleTestCase):
|
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):
|
def test_finds_tenant_through_parent_relation(self):
|
||||||
rack = FakeObject(tenant_id=42)
|
rack = FakeObject(tenant_id=42)
|
||||||
device = FakeObject(rack=rack)
|
device = FakeObject(rack=rack)
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ class TopologyViewsRackWidthTest(SimpleTestCase):
|
|||||||
self.assertIn('id="netbox-utilities-topology-rack-width-styles"', html)
|
self.assertIn('id="netbox-utilities-topology-rack-width-styles"', html)
|
||||||
self.assertIn('.rack-device[href="/dcim/devices/334/"]', html)
|
self.assertIn('.rack-device[href="/dcim/devices/334/"]', html)
|
||||||
self.assertIn("left: calc(50% + 3px) !important", 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(0% + 3px)!important", html)
|
||||||
self.assertIn("left:calc(50% + 3px)!important", html)
|
self.assertIn("left:calc(50% + 3px)!important", html)
|
||||||
self.assertIn("width:calc(50% - 6px)!important", html)
|
self.assertIn("width:calc(50% - 6px)!important", html)
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "netbox-utilities"
|
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"
|
description = "Navigation, tenant utilities, connection VLANs, partial-width racks, and bulk operations for NetBox 4.6"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
|||||||
Reference in New Issue
Block a user