|
|
@@ -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,
|
|
|
)
|
|
|
|
|
|
|