15794 Make "related objects" dynamic (#15876)

* Closes #15794: Make "related objects" dynamic

Instead of hardcoding relationships between models for the detail view,
they are now dynamically generated.

* Fix related models call

* Remove extra related models hook

Instead of providing a rarely used hook method, additional related
models can now be passed directly to the lookup method.

* Fix relations view for ASNs

ASNs have ManyToMany relationships and therefore can't used automatic
resolving. Explicit relations have been restored as before.

* Add method call keywords for clarification

* Cleanup related models

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
This commit is contained in:
Alexander Haase
2024-06-12 15:46:41 +02:00
committed by GitHub
parent 763d65bed9
commit 5353f83710
9 changed files with 176 additions and 238 deletions

View File

@@ -1,3 +1,5 @@
from typing import Iterable
from django.contrib.auth.mixins import AccessMixin
from django.core.exceptions import ImproperlyConfigured
from django.urls import reverse
@@ -6,10 +8,12 @@ from django.utils.translation import gettext_lazy as _
from netbox.plugins import PluginConfig
from netbox.registry import registry
from utilities.relations import get_related_models
from .permissions import resolve_permission
__all__ = (
'ContentTypePermissionRequiredMixin',
'GetRelatedModelsMixin',
'GetReturnURLMixin',
'ObjectPermissionRequiredMixin',
'ViewTab',
@@ -142,6 +146,46 @@ class GetReturnURLMixin:
return reverse('home')
class GetRelatedModelsMixin:
"""
Provides logic for collecting all related models for the currently viewed model.
"""
def get_related_models(self, request, instance, omit=[], extra=[]):
"""
Get related models of the view's `queryset` model without those listed in `omit`. Will be sorted alphabetical.
Args:
request: Current request being processed.
instance: The instance related models should be looked up for. A list of instances can be passed to match
related objects in this list (e.g. to find sites of a region including child regions).
omit: Remove relationships to these models from the result. Needs to be passed, if related models don't
provide a `_list` view.
extra: Add extra models to the list of automatically determined related models. Can be used to add indirect
relationships.
"""
model = self.queryset.model
related = filter(
lambda m: m[0] is not model and m[0] not in omit,
get_related_models(model, False)
)
related_models = [
(
model.objects.restrict(request.user, 'view').filter(**(
{f'{field}__in': instance}
if isinstance(instance, Iterable)
else {field: instance}
)),
f'{field}_id'
)
for model, field in related
]
related_models.extend(extra)
return sorted(related_models, key=lambda x: x[0].model._meta.verbose_name.lower())
class ViewTab:
"""
ViewTabs are used for navigation among multiple object-specific views, such as the changelog or journal for