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

Closes #18147: Include device & VM interfaces in VRF related objects (#20158)

Jeremy Stretch 5 месяцев назад
Родитель
Сommit
66140fc017
3 измененных файлов с 52 добавлено и 18 удалено
  1. 19 1
      netbox/ipam/views.py
  2. 12 12
      netbox/templates/inc/panels/related_objects.html
  3. 21 5
      netbox/utilities/views.py

+ 19 - 1
netbox/ipam/views.py

@@ -53,8 +53,26 @@ class VRFView(GetRelatedModelsMixin, generic.ObjectView):
         )
         export_targets_table.configure(request)
 
+        related_models = self.get_related_models(
+            request,
+            instance,
+            omit=(Interface, VMInterface),
+            extra=(
+                (
+                    Interface.objects.restrict(request.user, 'view').filter(vrf=instance),
+                    'vrf_id',
+                    _('Device Interfaces')
+                ),
+                (
+                    VMInterface.objects.restrict(request.user, 'view').filter(vrf=instance),
+                    'vrf_id',
+                    _('VM Interfaces')
+                ),
+            ),
+        )
+
         return {
-            'related_models': self.get_related_models(request, instance, omit=[Interface, VMInterface]),
+            'related_models': related_models,
             'import_targets_table': import_targets_table,
             'export_targets_table': export_targets_table,
         }

+ 12 - 12
netbox/templates/inc/panels/related_objects.html

@@ -4,19 +4,19 @@
 <div class="card">
   <h2 class="card-header">{% trans "Related Objects" %}</h2>
   <ul class="list-group list-group-flush" role="presentation">
-    {% for qs, filter_param in related_models %}
-      {% with viewname=qs.model|validated_viewname:"list" %}
+    {% for related_object_count in related_models %}
+      {% with viewname=related_object_count.queryset.model|validated_viewname:"list" %}
         {% if viewname is not None %}
-        <a href="{% url viewname %}?{{ filter_param }}={{ object.pk }}" class="list-group-item list-group-item-action d-flex justify-content-between">
-          {{ qs.model|meta:"verbose_name_plural"|bettertitle }}
-          {% with count=qs.count %}
-            {% if count %}
-              <span class="badge text-bg-primary rounded-pill">{{ count }}</span>
-            {% else %}
-              <span class="badge text-bg-light rounded-pill">&mdash;</span>
-            {% endif %}
-          {% endwith %}
-        </a>
+          <a href="{% url viewname %}?{{ related_object_count.filter_param }}={{ object.pk }}" class="list-group-item list-group-item-action d-flex justify-content-between">
+            {{ related_object_count.name }}
+            {% with count=related_object_count.queryset.count %}
+              {% if count %}
+                <span class="badge text-bg-primary rounded-pill">{{ count }}</span>
+              {% else %}
+                <span class="badge text-bg-light rounded-pill">&mdash;</span>
+              {% endif %}
+            {% endwith %}
+          </a>
         {% endif %}
       {% endwith %}
     {% empty %}

+ 21 - 5
netbox/utilities/views.py

@@ -1,8 +1,10 @@
+from dataclasses import dataclass
 from typing import Iterable
 
 from django.conf import settings
 from django.contrib.auth.mixins import AccessMixin
 from django.core.exceptions import ImproperlyConfigured
+from django.db.models import QuerySet
 from django.urls import reverse
 from django.urls.exceptions import NoReverseMatch
 from django.utils.translation import gettext_lazy as _
@@ -12,6 +14,7 @@ from netbox.plugins import PluginConfig
 from netbox.registry import registry
 from utilities.relations import get_related_models
 from utilities.request import safe_for_redirect
+from utilities.string import title
 from .permissions import resolve_permission
 
 __all__ = (
@@ -177,8 +180,17 @@ class GetRelatedModelsMixin:
     """
     Provides logic for collecting all related models for the currently viewed model.
     """
+    @dataclass
+    class RelatedObjectCount:
+        queryset: QuerySet
+        filter_param: str
+        label: str = ''
 
-    def get_related_models(self, request, instance, omit=[], extra=[]):
+        @property
+        def name(self):
+            return self.label or title(_(self.queryset.model._meta.verbose_name_plural))
+
+    def get_related_models(self, request, instance, omit=None, extra=None):
         """
         Get related models of the view's `queryset` model without those listed in `omit`. Will be sorted alphabetical.
 
@@ -191,6 +203,7 @@ class GetRelatedModelsMixin:
             extra: Add extra models to the list of automatically determined related models. Can be used to add indirect
                 relationships.
         """
+        omit = omit or []
         model = self.queryset.model
         related = filter(
             lambda m: m[0] is not model and m[0] not in omit,
@@ -198,7 +211,7 @@ class GetRelatedModelsMixin:
         )
 
         related_models = [
-            (
+            self.RelatedObjectCount(
                 model.objects.restrict(request.user, 'view').filter(**(
                     {f'{field}__in': instance}
                     if isinstance(instance, Iterable)
@@ -208,11 +221,14 @@ class GetRelatedModelsMixin:
             )
             for model, field in related
         ]
-        related_models.extend(extra)
+        if extra is not None:
+            related_models.extend([
+                self.RelatedObjectCount(*attrs) for attrs in extra
+            ])
 
         return sorted(
-            filter(lambda qs: qs[0].exists(), related_models),
-            key=lambda qs: qs[0].model._meta.verbose_name.lower(),
+            filter(lambda roc: roc.queryset.exists(), related_models),
+            key=lambda roc: roc.name,
         )