Просмотр исходного кода

Standardize related model display for organizational models

jeremystretch 3 лет назад
Родитель
Сommit
94797bb956

+ 9 - 0
netbox/circuits/views.py

@@ -127,6 +127,15 @@ class CircuitTypeListView(generic.ObjectListView):
 class CircuitTypeView(generic.ObjectView):
     queryset = CircuitType.objects.all()
 
+    def get_extra_context(self, request, instance):
+        related_models = (
+            (Circuit.objects.restrict(request.user, 'view').filter(type=instance), 'type_id'),
+        )
+
+        return {
+            'related_models': related_models,
+        }
+
 
 @register_model_view(CircuitType, 'edit')
 class CircuitTypeEditView(generic.ObjectEditView):

+ 27 - 52
netbox/dcim/views.py

@@ -543,6 +543,15 @@ class RackRoleListView(generic.ObjectListView):
 class RackRoleView(generic.ObjectView):
     queryset = RackRole.objects.all()
 
+    def get_extra_context(self, request, instance):
+        related_models = (
+            (Rack.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
+        )
+
+        return {
+            'related_models': related_models,
+        }
+
 
 @register_model_view(RackRole, 'edit')
 class RackRoleEditView(generic.ObjectEditView):
@@ -803,20 +812,15 @@ class ManufacturerView(generic.ObjectView):
     queryset = Manufacturer.objects.all()
 
     def get_extra_context(self, request, instance):
-        device_types = DeviceType.objects.restrict(request.user, 'view').filter(
-            manufacturer=instance
-        )
-        module_types = ModuleType.objects.restrict(request.user, 'view').filter(
-            manufacturer=instance
-        )
-        inventory_items = InventoryItem.objects.restrict(request.user, 'view').filter(
-            manufacturer=instance
+        related_models = (
+            (DeviceType.objects.restrict(request.user, 'view').filter(manufacturer=instance), 'manufacturer_id'),
+            (ModuleType.objects.restrict(request.user, 'view').filter(manufacturer=instance), 'manufacturer_id'),
+            (InventoryItem.objects.restrict(request.user, 'view').filter(manufacturer=instance), 'manufacturer_id'),
+            (Platform.objects.restrict(request.user, 'view').filter(manufacturer=instance), 'manufacturer_id'),
         )
 
         return {
-            'devicetype_count': device_types.count(),
-            'inventoryitem_count': inventory_items.count(),
-            'moduletype_count': module_types.count(),
+            'related_models': related_models,
         }
 
 
@@ -1667,41 +1671,15 @@ class DeviceRoleListView(generic.ObjectListView):
 class DeviceRoleView(generic.ObjectView):
     queryset = DeviceRole.objects.all()
 
+    def get_extra_context(self, request, instance):
+        related_models = (
+            (Device.objects.restrict(request.user, 'view').filter(device_role=instance), 'role_id'),
+            (VirtualMachine.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
+        )
 
-@register_model_view(DeviceRole, 'devices', path='devices')
-class DeviceRoleDevicesView(generic.ObjectChildrenView):
-    queryset = DeviceRole.objects.all()
-    child_model = Device
-    table = tables.DeviceTable
-    filterset = filtersets.DeviceFilterSet
-    template_name = 'dcim/devicerole/devices.html'
-    tab = ViewTab(
-        label=_('Devices'),
-        badge=lambda obj: obj.devices.count(),
-        permission='dcim.view_device',
-        weight=400
-    )
-
-    def get_children(self, request, parent):
-        return Device.objects.restrict(request.user, 'view').filter(device_role=parent)
-
-
-@register_model_view(DeviceRole, 'virtual_machines', path='virtual-machines')
-class DeviceRoleVirtualMachinesView(generic.ObjectChildrenView):
-    queryset = DeviceRole.objects.all()
-    child_model = VirtualMachine
-    table = VirtualMachineTable
-    filterset = VirtualMachineFilterSet
-    template_name = 'dcim/devicerole/virtual_machines.html'
-    tab = ViewTab(
-        label=_('Virtual machines'),
-        badge=lambda obj: obj.virtual_machines.count(),
-        permission='virtualization.view_virtualmachine',
-        weight=500
-    )
-
-    def get_children(self, request, parent):
-        return VirtualMachine.objects.restrict(request.user, 'view').filter(role=parent)
+        return {
+            'related_models': related_models,
+        }
 
 
 @register_model_view(DeviceRole, 'edit')
@@ -1758,16 +1736,13 @@ class PlatformView(generic.ObjectView):
     queryset = Platform.objects.all()
 
     def get_extra_context(self, request, instance):
-        devices = Device.objects.restrict(request.user, 'view').filter(
-            platform=instance
-        )
-        virtual_machines = VirtualMachine.objects.restrict(request.user, 'view').filter(
-            platform=instance
+        related_models = (
+            (Device.objects.restrict(request.user, 'view').filter(platform=instance), 'platform_id'),
+            (VirtualMachine.objects.restrict(request.user, 'view').filter(platform=instance), 'platform_id'),
         )
 
         return {
-            'device_count': devices.count(),
-            'virtualmachine_count': virtual_machines.count()
+            'related_models': related_models,
         }
 
 

+ 26 - 1
netbox/ipam/views.py

@@ -165,6 +165,15 @@ class RIRListView(generic.ObjectListView):
 class RIRView(generic.ObjectView):
     queryset = RIR.objects.all()
 
+    def get_extra_context(self, request, instance):
+        related_models = (
+            (Aggregate.objects.restrict(request.user, 'view').filter(rir=instance), 'rir_id'),
+        )
+
+        return {
+            'related_models': related_models,
+        }
+
 
 @register_model_view(RIR, 'edit')
 class RIREditView(generic.ObjectEditView):
@@ -368,6 +377,17 @@ class RoleListView(generic.ObjectListView):
 class RoleView(generic.ObjectView):
     queryset = Role.objects.all()
 
+    def get_extra_context(self, request, instance):
+        related_models = (
+            (Prefix.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
+            (IPRange.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
+            (VLAN.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
+        )
+
+        return {
+            'related_models': related_models,
+        }
+
 
 @register_model_view(Role, 'edit')
 class RoleEditView(generic.ObjectEditView):
@@ -839,6 +859,11 @@ class VLANGroupView(generic.ObjectView):
     queryset = VLANGroup.objects.all()
 
     def get_extra_context(self, request, instance):
+        related_models = (
+            (VLAN.objects.restrict(request.user, 'view').filter(group=instance), 'group_id'),
+        )
+
+        # TODO: Replace with embedded table
         vlans = VLAN.objects.restrict(request.user, 'view').filter(group=instance).prefetch_related(
             Prefetch('prefixes', queryset=Prefix.objects.restrict(request.user)),
             'tenant', 'site', 'role',
@@ -852,7 +877,7 @@ class VLANGroupView(generic.ObjectView):
         vlans_table.configure(request)
 
         return {
-            'vlans_count': vlans_count,
+            'related_models': related_models,
             'vlans_table': vlans_table,
         }
 

+ 1 - 13
netbox/templates/circuits/circuittype.html

@@ -28,12 +28,6 @@
             <th scope="row">Description</th>
             <td>{{ object.description|placeholder }}</td>
           </tr>
-          <tr>
-            <th scope="row">Circuits</th>
-            <td>
-              <a href="{% url 'circuits:circuit_list' %}?type_id={{ object.pk }}">{{ object.circuits.count }}</a>
-            </td>
-          </tr>
         </table>
       </div>
     </div>
@@ -41,19 +35,13 @@
     {% plugin_left_page object %}
   </div>
 	<div class="col col-md-6">
+      {% include 'inc/panels/related_objects.html' %}
     {% include 'inc/panels/custom_fields.html' %}
     {% plugin_right_page object %}
 	</div>
 </div>
 <div class="row mb-3">
 	<div class="col col-md-12">
-    <div class="card">
-      <h5 class="card-header">Circuits</h5>
-      <div class="card-body htmx-container table-responsive"
-        hx-get="{% url 'circuits:circuit_list' %}?type_id={{ object.pk }}"
-        hx-trigger="load"
-      ></div>
-    </div>
     {% plugin_full_width_page object %}
   </div>
 </div>

+ 1 - 16
netbox/templates/dcim/devicerole.html

@@ -42,22 +42,6 @@
             <th scope="row">VM Role</th>
             <td>{% checkmark object.vm_role %}</td>
           </tr>
-          <tr>
-            <th scope="row">Devices</th>
-            <td>
-              <a href="{% url 'dcim:device_list' %}?role_id={{ object.pk }}">{{ object.devices.count }}</a>
-            </td>
-          </tr>
-          <tr>
-            <th>Virtual Machines</th>
-            <td>
-              {% if object.vm_role %}
-                <a href="{% url 'virtualization:virtualmachine_list' %}?role_id={{ object.pk }}">{{ object.virtual_machines.count }}</a>
-              {% else %}
-                {{ ''|placeholder }}
-              {% endif %}
-            </td>
-          </tr>
         </table>
       </div>
     </div>
@@ -65,6 +49,7 @@
     {% plugin_left_page object %}
 	</div>
 	<div class="col col-md-6">
+    {% include 'inc/panels/related_objects.html' %}
     {% include 'inc/panels/custom_fields.html' %}
     {% plugin_right_page object %}
   </div>

+ 0 - 20
netbox/templates/dcim/devicerole/devices.html

@@ -1,20 +0,0 @@
-{% extends 'dcim/devicerole.html' %}
-{% load helpers %}
-{% load render_table from django_tables2 %}
-
-{% block content %}
-    {% include 'inc/table_controls_htmx.html' with table_modal='DeviceTable_config' %}
-    <form method="post">
-        {% csrf_token %}
-        <div class="card">
-            <div class="card-body" id="object_list">
-                {% include 'htmx/table.html' %}
-            </div>
-        </div>
-    </form>
-{% endblock content %}
-
-{% block modals %}
-    {{ block.super }}
-    {% table_config_form table %}
-{% endblock modals %}

+ 0 - 20
netbox/templates/dcim/devicerole/virtual_machines.html

@@ -1,20 +0,0 @@
-{% extends 'dcim/devicerole.html' %}
-{% load helpers %}
-{% load render_table from django_tables2 %}
-
-{% block content %}
-    {% include 'inc/table_controls_htmx.html' with table_modal='VirtualMachineTable_config' %}
-    <form method="post">
-        {% csrf_token %}
-        <div class="card">
-            <div class="card-body" id="object_list">
-                {% include 'htmx/table.html' %}
-            </div>
-        </div>
-    </form>
-{% endblock content %}
-
-{% block modals %}
-    {{ block.super }}
-    {% table_config_form table %}
-{% endblock modals %}

+ 1 - 25
netbox/templates/dcim/manufacturer.html

@@ -42,24 +42,6 @@
             <th scope="row">Description</th>
             <td>{{ object.description|placeholder }}</td>
           </tr>
-          <tr>
-            <th scope="row">Device types</th>
-            <td>
-              <a href="{% url 'dcim:devicetype_list' %}?manufacturer_id={{ object.pk }}">{{ devicetype_count }}</a>
-            </td>
-          </tr>
-          <tr>
-            <th scope="row">Module types</th>
-            <td>
-              <a href="{% url 'dcim:moduletype_list' %}?manufacturer_id={{ object.pk }}">{{ moduletype_count }}</a>
-            </td>
-          </tr>
-          <tr>
-            <th scope="row">Inventory Items</th>
-            <td>
-              <a href="{% url 'dcim:inventoryitem_list' %}?manufacturer_id={{ object.pk }}">{{ inventoryitem_count }}</a>
-            </td>
-          </tr>
         </table>
       </div>
     </div>
@@ -67,6 +49,7 @@
     {% plugin_left_page object %}
 	</div>
 	<div class="col col-md-6">
+    {% include 'inc/panels/related_objects.html' %}
     {% include 'inc/panels/custom_fields.html' %}
     {% include 'inc/panels/contacts.html' %}
     {% plugin_right_page object %}
@@ -74,13 +57,6 @@
 </div>
 <div class="row mb-3">
 	<div class="col col-md-12">
-    <div class="card">
-      <h5 class="card-header">Device Types</h5>
-      <div class="card-body htmx-container table-responsive"
-        hx-get="{% url 'dcim:devicetype_list' %}?manufacturer_id={{ object.pk }}"
-        hx-trigger="load"
-      ></div>
-    </div>
     {% plugin_full_width_page object %}
   </div>
 </div>

+ 5 - 25
netbox/templates/dcim/platform.html

@@ -43,46 +43,26 @@
             <th scope="row">NAPALM Driver</th>
             <td>{{ object.napalm_driver|placeholder }}</td>
           </tr>
-          <tr>
-            <th scope="row">Devices</th>
-            <td>
-              <a href="{% url 'dcim:device_list' %}?platform_id={{ object.pk }}">{{ device_count }}</a>
-            </td>
-          </tr>
-          <tr>
-            <th scope="row">Virtual Machines</th>
-            <td>
-              <a href="{% url 'virtualization:virtualmachine_list' %}?platform_id={{ object.pk }}">{{ virtualmachine_count }}</a>
-            </td>
-          </tr>
         </table>
       </div>
     </div>
     {% include 'inc/panels/tags.html' %}
-    {% plugin_left_page object %}
-	</div>
-	<div class="col col-md-6">
     <div class="card">
-      <h5 class="card-header">
-        NAPALM Arguments
-      </h5>
+      <h5 class="card-header">NAPALM Arguments</h5>
       <div class="card-body">
         <pre>{{ object.napalm_args|json }}</pre>
       </div>
     </div>
+    {% plugin_left_page object %}
+	</div>
+	<div class="col col-md-6">
+    {% include 'inc/panels/related_objects.html' %}
     {% include 'inc/panels/custom_fields.html' %}
     {% plugin_right_page object %}
   </div>
 </div>
 <div class="row mb-3">
 	<div class="col col-md-12">
-    <div class="card">
-      <h5 class="card-header">Devices</h5>
-      <div class="card-body htmx-container table-responsive"
-        hx-get="{% url 'dcim:device_list' %}?platform_id={{ object.pk }}"
-        hx-trigger="load"
-      ></div>
-    </div>
     {% plugin_full_width_page object %}
   </div>
 </div>

+ 1 - 13
netbox/templates/dcim/rackrole.html

@@ -34,12 +34,6 @@
               <span class="badge color-label" style="background-color: #{{ object.color }}">&nbsp;</span>
             </td>
           </tr>
-          <tr>
-            <th scope="row">Racks</th>
-            <td>
-              <a href="{% url 'dcim:rack_list' %}?role_id={{ object.pk }}">{{ object.racks.count }}</a>
-            </td>
-          </tr>
         </table>
       </div>
     </div>
@@ -47,19 +41,13 @@
     {% plugin_left_page object %}
 	</div>
 	<div class="col col-md-6">
+    {% include 'inc/panels/related_objects.html' %}
     {% include 'inc/panels/custom_fields.html' %}
     {% plugin_right_page object %}
   </div>
 </div>
 <div class="row mb-3">
 	<div class="col col-md-12">
-    <div class="card">
-      <h5 class="card-header">Racks</h5>
-      <div class="card-body htmx-container table-responsive"
-        hx-get="{% url 'dcim:rack_list' %}?role_id={{ object.pk }}"
-        hx-trigger="load"
-      ></div>
-    </div>
     {% plugin_full_width_page object %}
   </div>
 </div>

+ 2 - 14
netbox/templates/ipam/rir.html

@@ -32,32 +32,20 @@
             <th scope="row">Private</th>
             <td>{% checkmark object.is_private %}</td>
           </tr>
-          <tr>
-            <th scope="row">Aggregates</th>
-            <td>
-              <a href="{% url 'ipam:aggregate_list' %}?rir_id={{ object.pk }}">{{ object.aggregates.count }}</a>
-            </td>
-          </tr>
         </table>
       </div>
     </div>
+    {% include 'inc/panels/tags.html' %}
     {% plugin_left_page object %}
 	</div>
 	<div class="col col-md-6">
-    {% include 'inc/panels/tags.html' %}
+    {% include 'inc/panels/related_objects.html' %}
     {% include 'inc/panels/custom_fields.html' %}
     {% plugin_right_page object %}
   </div>
 </div>
 <div class="row mb-3">
 	<div class="col col-md-12">
-    <div class="card">
-      <h5 class="card-header">Aggregates</h5>
-      <div class="card-body htmx-container table-responsive"
-        hx-get="{% url 'ipam:aggregate_list' %}?rir_id={{ object.pk }}"
-        hx-trigger="load"
-      ></div>
-    </div>
     {% plugin_full_width_page object %}
   </div>
 </div>

+ 2 - 26
netbox/templates/ipam/role.html

@@ -32,44 +32,20 @@
             <th scope="row">Weight</th>
             <td>{{ object.weight }}</td>
           </tr>
-          <tr>
-            <th scope="row">Prefixes</th>
-            <td>
-              <a href="{% url 'ipam:prefix_list' %}?role_id={{ object.pk }}">{{ object.prefixes.count }}</a>
-            </td>
-          </tr>
-          <tr>
-            <th scope="row">IP Ranges</th>
-            <td>
-              <a href="{% url 'ipam:iprange_list' %}?role_id={{ object.pk }}">{{ object.ip_ranges.count }}</a>
-            </td>
-          </tr>
-          <tr>
-            <th scope="row">VLANs</th>
-            <td>
-              <a href="{% url 'ipam:vlan_list' %}?role_id={{ object.pk }}">{{ object.vlans.count }}</a>
-            </td>
-          </tr>
         </table>
       </div>
     </div>
+    {% include 'inc/panels/tags.html' %}
     {% plugin_left_page object %}
 	</div>
 	<div class="col col-md-6">
-    {% include 'inc/panels/tags.html' %}
+    {% include 'inc/panels/related_objects.html' %}
     {% include 'inc/panels/custom_fields.html' %}
     {% plugin_right_page object %}
   </div>
 </div>
 <div class="row mb-3">
 	<div class="col col-md-12">
-    <div class="card">
-      <h5 class="card-header">Prefixes</h5>
-      <div class="card-body htmx-container table-responsive"
-        hx-get="{% url 'ipam:prefix_list' %}?role_id={{ object.pk }}"
-        hx-trigger="load"
-      ></div>
-    </div>
     {% plugin_full_width_page object %}
   </div>
 </div>

+ 1 - 6
netbox/templates/ipam/vlangroup.html

@@ -42,12 +42,6 @@
             <th scope="row">Permitted VIDs</th>
             <td>{{ object.min_vid }} - {{ object.max_vid }}</td>
           </tr>
-          <tr>
-            <th scope="row">VLANs</th>
-            <td>
-              <a href="{% url 'ipam:vlan_list' %}?group_id={{ object.pk }}">{{ vlans_count }}</a>
-            </td>
-          </tr>
         </table>
       </div>
     </div>
@@ -55,6 +49,7 @@
     {% plugin_left_page object %}
 	</div>
 	<div class="col col-md-6">
+    {% include 'inc/panels/related_objects.html' %}
     {% include 'inc/panels/custom_fields.html' %}
     {% plugin_right_page object %}
   </div>

+ 1 - 13
netbox/templates/virtualization/clustergroup.html

@@ -28,12 +28,6 @@
             <th scope="row">Description</th>
             <td>{{ object.description|placeholder }}</td>
           </tr>
-          <tr>
-            <th scope="row">Clusters</th>
-            <td>
-              <a href="{% url 'virtualization:cluster_list' %}?group_id={{ object.pk }}">{{ object.clusters.count }}</a>
-            </td>
-          </tr>
         </table>
       </div>
     </div>
@@ -41,6 +35,7 @@
     {% plugin_left_page object %}
 	</div>
 	<div class="col col-md-6">
+    {% include 'inc/panels/related_objects.html' %}
     {% include 'inc/panels/custom_fields.html' %}
     {% include 'inc/panels/contacts.html' %}
     {% plugin_right_page object %}
@@ -48,13 +43,6 @@
 </div>
 <div class="row">
 	<div class="col col-md-12">
-    <div class="card">
-      <h5 class="card-header">Clusters</h5>
-      <div class="card-body htmx-container table-responsive"
-        hx-get="{% url 'virtualization:cluster_list' %}?group_id={{ object.pk }}"
-        hx-trigger="load"
-      ></div>
-    </div>
     {% plugin_full_width_page object %}
   </div>
 </div>

+ 1 - 7
netbox/templates/virtualization/clustertype.html

@@ -41,19 +41,13 @@
     {% plugin_left_page object %}
 	</div>
 	<div class="col col-md-6">
+    {% include 'inc/panels/related_objects.html' %}
     {% include 'inc/panels/custom_fields.html' %}
     {% plugin_right_page object %}
   </div>
 </div>
 <div class="row">
 	<div class="col col-md-12">
-    <div class="card">
-      <h5 class="card-header">Clusters</h5>
-      <div class="card-body htmx-container table-responsive"
-        hx-get="{% url 'virtualization:cluster_list' %}?type_id={{ object.pk }}"
-        hx-trigger="load"
-      ></div>
-    </div>
     {% plugin_full_width_page object %}
   </div>
 </div>

+ 13 - 9
netbox/virtualization/views.py

@@ -10,7 +10,7 @@ from dcim.models import Device
 from dcim.tables import DeviceTable
 from extras.views import ObjectConfigContextView
 from ipam.models import IPAddress, Service
-from ipam.tables import AssignedIPAddressesTable, InterfaceVLANTable
+from ipam.tables import InterfaceVLANTable
 from netbox.views import generic
 from utilities.utils import count_related
 from utilities.views import ViewTab, register_model_view
@@ -36,17 +36,12 @@ class ClusterTypeView(generic.ObjectView):
     queryset = ClusterType.objects.all()
 
     def get_extra_context(self, request, instance):
-        clusters = Cluster.objects.restrict(request.user, 'view').filter(
-            type=instance
-        ).annotate(
-            device_count=count_related(Device, 'cluster'),
-            vm_count=count_related(VirtualMachine, 'cluster')
+        related_models = (
+            (Cluster.objects.restrict(request.user, 'view').filter(type=instance), 'type_id'),
         )
-        clusters_table = tables.ClusterTable(clusters, user=request.user, exclude=('type',))
-        clusters_table.configure(request)
 
         return {
-            'clusters_table': clusters_table,
+            'related_models': related_models,
         }
 
 
@@ -100,6 +95,15 @@ class ClusterGroupListView(generic.ObjectListView):
 class ClusterGroupView(generic.ObjectView):
     queryset = ClusterGroup.objects.all()
 
+    def get_extra_context(self, request, instance):
+        related_models = (
+            (Cluster.objects.restrict(request.user, 'view').filter(group=instance), 'group_id'),
+        )
+
+        return {
+            'related_models': related_models,
+        }
+
 
 @register_model_view(ClusterGroup, 'edit')
 class ClusterGroupEditView(generic.ObjectEditView):