Przeglądaj źródła

Closes #13794: Dynamically populate related objects list under tenant view (#14196)

* Closes #13794: Dynamically populate related objects list under tenant view

* get_related_models() should sort models alphabetically by default

* Reference Meta.related_objects instead of calling get_fields()
Jeremy Stretch 2 lat temu
rodzic
commit
69a4c31072
2 zmienionych plików z 21 dodań i 33 usunięć
  1. 3 32
      netbox/tenancy/views.py
  2. 18 1
      netbox/utilities/utils.py

+ 3 - 32
netbox/tenancy/views.py

@@ -2,14 +2,9 @@ from django.contrib.contenttypes.models import ContentType
 from django.shortcuts import get_object_or_404
 from django.shortcuts import get_object_or_404
 from django.utils.translation import gettext as _
 from django.utils.translation import gettext as _
 
 
-from circuits.models import Circuit
-from dcim.models import Cable, Device, Location, PowerFeed, Rack, RackReservation, Site, VirtualDeviceContext
-from ipam.models import Aggregate, ASN, IPAddress, IPRange, L2VPN, Prefix, VLAN, VRF
 from netbox.views import generic
 from netbox.views import generic
-from utilities.utils import count_related
+from utilities.utils import count_related, get_related_models
 from utilities.views import register_model_view, ViewTab
 from utilities.views import register_model_view, ViewTab
-from virtualization.models import VirtualMachine, Cluster
-from wireless.models import WirelessLAN, WirelessLink
 from . import filtersets, forms, tables
 from . import filtersets, forms, tables
 from .models import *
 from .models import *
 
 
@@ -132,32 +127,8 @@ class TenantView(generic.ObjectView):
 
 
     def get_extra_context(self, request, instance):
     def get_extra_context(self, request, instance):
         related_models = [
         related_models = [
-            # DCIM
-            (Site.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (Rack.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (RackReservation.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (Location.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (Device.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (VirtualDeviceContext.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (Cable.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (PowerFeed.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            # IPAM
-            (VRF.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (Aggregate.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (Prefix.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (IPRange.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (IPAddress.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (ASN.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (VLAN.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (L2VPN.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            # Circuits
-            (Circuit.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            # Virtualization
-            (VirtualMachine.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (Cluster.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            # Wireless
-            (WirelessLAN.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
-            (WirelessLink.objects.restrict(request.user, 'view').filter(tenant=instance), 'tenant_id'),
+            (model.objects.restrict(request.user, 'view').filter(tenant=instance), f'{field}_id')
+            for model, field in get_related_models(Tenant)
         ]
         ]
 
 
         return {
         return {

+ 18 - 1
netbox/utilities/utils.py

@@ -8,7 +8,7 @@ from itertools import count, groupby
 import bleach
 import bleach
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 from django.core import serializers
 from django.core import serializers
-from django.db.models import Count, OuterRef, Subquery
+from django.db.models import Count, ManyToOneRel, OuterRef, Subquery
 from django.db.models.functions import Coalesce
 from django.db.models.functions import Coalesce
 from django.http import QueryDict
 from django.http import QueryDict
 from django.utils import timezone
 from django.utils import timezone
@@ -567,3 +567,20 @@ def local_now():
     Return the current date & time in the system timezone.
     Return the current date & time in the system timezone.
     """
     """
     return localtime(timezone.now())
     return localtime(timezone.now())
+
+
+def get_related_models(model, ordered=True):
+    """
+    Return a list of all models which have a ForeignKey to the given model and the name of the field. For example,
+    `get_related_models(Tenant)` will return all models which have a ForeignKey relationship to Tenant.
+    """
+    related_models = [
+        (field.related_model, field.remote_field.name)
+        for field in model._meta.related_objects
+        if type(field) is ManyToOneRel
+    ]
+
+    if ordered:
+        return sorted(related_models, key=lambda x: x[0]._meta.verbose_name)
+
+    return related_models