diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py
index 8efa06191..37e56ff3d 100644
--- a/netbox/ipam/views.py
+++ b/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,
}
diff --git a/netbox/templates/inc/panels/related_objects.html b/netbox/templates/inc/panels/related_objects.html
index c013c14c5..7e59e38c1 100644
--- a/netbox/templates/inc/panels/related_objects.html
+++ b/netbox/templates/inc/panels/related_objects.html
@@ -4,19 +4,19 @@
- {% 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 %}
-
- {{ qs.model|meta:"verbose_name_plural"|bettertitle }}
- {% with count=qs.count %}
- {% if count %}
- {{ count }}
- {% else %}
- —
- {% endif %}
- {% endwith %}
-
+
+ {{ related_object_count.name }}
+ {% with count=related_object_count.queryset.count %}
+ {% if count %}
+ {{ count }}
+ {% else %}
+ —
+ {% endif %}
+ {% endwith %}
+
{% endif %}
{% endwith %}
{% empty %}
diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py
index 5c6c7977d..b11c87179 100644
--- a/netbox/utilities/views.py
+++ b/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,
)