mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 01:41:22 -06:00
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:
parent
763d65bed9
commit
5353f83710
@ -7,7 +7,7 @@ from netbox.views import generic
|
|||||||
from tenancy.views import ObjectContactsView
|
from tenancy.views import ObjectContactsView
|
||||||
from utilities.forms import ConfirmationForm
|
from utilities.forms import ConfirmationForm
|
||||||
from utilities.query import count_related
|
from utilities.query import count_related
|
||||||
from utilities.views import register_model_view
|
from utilities.views import GetRelatedModelsMixin, register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
@ -26,17 +26,12 @@ class ProviderListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(Provider)
|
@register_model_view(Provider)
|
||||||
class ProviderView(generic.ObjectView):
|
class ProviderView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Provider.objects.all()
|
queryset = Provider.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(ProviderAccount.objects.restrict(request.user, 'view').filter(provider=instance), 'provider_id'),
|
|
||||||
(Circuit.objects.restrict(request.user, 'view').filter(provider=instance), 'provider_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -92,16 +87,12 @@ class ProviderAccountListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(ProviderAccount)
|
@register_model_view(ProviderAccount)
|
||||||
class ProviderAccountView(generic.ObjectView):
|
class ProviderAccountView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = ProviderAccount.objects.all()
|
queryset = ProviderAccount.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Circuit.objects.restrict(request.user, 'view').filter(provider_account=instance), 'provider_account_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -156,19 +147,21 @@ class ProviderNetworkListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(ProviderNetwork)
|
@register_model_view(ProviderNetwork)
|
||||||
class ProviderNetworkView(generic.ObjectView):
|
class ProviderNetworkView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = ProviderNetwork.objects.all()
|
queryset = ProviderNetwork.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(
|
|
||||||
Circuit.objects.restrict(request.user, 'view').filter(terminations__provider_network=instance),
|
|
||||||
'provider_network_id',
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(
|
||||||
|
request,
|
||||||
|
instance,
|
||||||
|
extra=(
|
||||||
|
(
|
||||||
|
Circuit.objects.restrict(request.user, 'view').filter(terminations__provider_network=instance),
|
||||||
|
'provider_network_id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -215,16 +208,12 @@ class CircuitTypeListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(CircuitType)
|
@register_model_view(CircuitType)
|
||||||
class CircuitTypeView(generic.ObjectView):
|
class CircuitTypeView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = CircuitType.objects.all()
|
queryset = CircuitType.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Circuit.objects.restrict(request.user, 'view').filter(type=instance), 'type_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ from netbox.views.generic.mixins import TableMixin
|
|||||||
from utilities.forms import ConfirmationForm
|
from utilities.forms import ConfirmationForm
|
||||||
from utilities.htmx import htmx_partial
|
from utilities.htmx import htmx_partial
|
||||||
from utilities.query import count_related
|
from utilities.query import count_related
|
||||||
from utilities.views import ContentTypePermissionRequiredMixin, register_model_view
|
from utilities.views import ContentTypePermissionRequiredMixin, GetRelatedModelsMixin, register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
@ -51,16 +51,12 @@ class DataSourceListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(DataSource)
|
@register_model_view(DataSource)
|
||||||
class DataSourceView(generic.ObjectView):
|
class DataSourceView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = DataSource.objects.all()
|
queryset = DataSource.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(DataFile.objects.restrict(request.user, 'view').filter(source=instance), 'source_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ from jinja2.exceptions import TemplateError
|
|||||||
|
|
||||||
from circuits.models import Circuit, CircuitTermination
|
from circuits.models import Circuit, CircuitTermination
|
||||||
from extras.views import ObjectConfigContextView
|
from extras.views import ObjectConfigContextView
|
||||||
from ipam.models import ASN, IPAddress, Prefix, VLAN, VLANGroup
|
from ipam.models import ASN, IPAddress, VLANGroup
|
||||||
from ipam.tables import InterfaceVLANTable
|
from ipam.tables import InterfaceVLANTable
|
||||||
from netbox.constants import DEFAULT_ACTION_PERMISSIONS
|
from netbox.constants import DEFAULT_ACTION_PERMISSIONS
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
@ -27,7 +27,9 @@ from utilities.paginator import EnhancedPaginator, get_paginate_count
|
|||||||
from utilities.permissions import get_permission_for_model
|
from utilities.permissions import get_permission_for_model
|
||||||
from utilities.query import count_related
|
from utilities.query import count_related
|
||||||
from utilities.query_functions import CollateAsChar
|
from utilities.query_functions import CollateAsChar
|
||||||
from utilities.views import GetReturnURLMixin, ObjectPermissionRequiredMixin, ViewTab, register_model_view
|
from utilities.views import (
|
||||||
|
GetRelatedModelsMixin, GetReturnURLMixin, ObjectPermissionRequiredMixin, ViewTab, register_model_view
|
||||||
|
)
|
||||||
from virtualization.filtersets import VirtualMachineFilterSet
|
from virtualization.filtersets import VirtualMachineFilterSet
|
||||||
from virtualization.models import VirtualMachine
|
from virtualization.models import VirtualMachine
|
||||||
from virtualization.tables import VirtualMachineTable
|
from virtualization.tables import VirtualMachineTable
|
||||||
@ -226,19 +228,21 @@ class RegionListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(Region)
|
@register_model_view(Region)
|
||||||
class RegionView(generic.ObjectView):
|
class RegionView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Region.objects.all()
|
queryset = Region.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
regions = instance.get_descendants(include_self=True)
|
regions = instance.get_descendants(include_self=True)
|
||||||
related_models = (
|
|
||||||
(Site.objects.restrict(request.user, 'view').filter(region__in=regions), 'region_id'),
|
|
||||||
(Location.objects.restrict(request.user, 'view').filter(site__region__in=regions), 'region_id'),
|
|
||||||
(Rack.objects.restrict(request.user, 'view').filter(site__region__in=regions), 'region_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(
|
||||||
|
request,
|
||||||
|
regions,
|
||||||
|
extra=(
|
||||||
|
(Location.objects.restrict(request.user, 'view').filter(site__region__in=regions), 'region_id'),
|
||||||
|
(Rack.objects.restrict(request.user, 'view').filter(site__region__in=regions), 'region_id'),
|
||||||
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -306,19 +310,21 @@ class SiteGroupListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(SiteGroup)
|
@register_model_view(SiteGroup)
|
||||||
class SiteGroupView(generic.ObjectView):
|
class SiteGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = SiteGroup.objects.all()
|
queryset = SiteGroup.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
groups = instance.get_descendants(include_self=True)
|
groups = instance.get_descendants(include_self=True)
|
||||||
related_models = (
|
|
||||||
(Site.objects.restrict(request.user, 'view').filter(group__in=groups), 'group_id'),
|
|
||||||
(Location.objects.restrict(request.user, 'view').filter(site__group__in=groups), 'site_group_id'),
|
|
||||||
(Rack.objects.restrict(request.user, 'view').filter(site__group__in=groups), 'site_group_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(
|
||||||
|
request,
|
||||||
|
groups,
|
||||||
|
extra=(
|
||||||
|
(Location.objects.restrict(request.user, 'view').filter(site__group__in=groups), 'site_group_id'),
|
||||||
|
(Rack.objects.restrict(request.user, 'view').filter(site__group__in=groups), 'site_group_id'),
|
||||||
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -380,31 +386,25 @@ class SiteListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(Site)
|
@register_model_view(Site)
|
||||||
class SiteView(generic.ObjectView):
|
class SiteView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Site.objects.prefetch_related('tenant__group')
|
queryset = Site.objects.prefetch_related('tenant__group')
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
# DCIM
|
|
||||||
(Location.objects.restrict(request.user, 'view').filter(site=instance), 'site_id'),
|
|
||||||
(Rack.objects.restrict(request.user, 'view').filter(site=instance), 'site_id'),
|
|
||||||
(Device.objects.restrict(request.user, 'view').filter(site=instance), 'site_id'),
|
|
||||||
# Virtualization
|
|
||||||
(VirtualMachine.objects.restrict(request.user, 'view').filter(cluster__site=instance), 'site_id'),
|
|
||||||
# IPAM
|
|
||||||
(Prefix.objects.restrict(request.user, 'view').filter(site=instance), 'site_id'),
|
|
||||||
(ASN.objects.restrict(request.user, 'view').filter(sites=instance), 'site_id'),
|
|
||||||
(VLANGroup.objects.restrict(request.user, 'view').filter(
|
|
||||||
scope_type=ContentType.objects.get_for_model(Site),
|
|
||||||
scope_id=instance.pk
|
|
||||||
), 'site'),
|
|
||||||
(VLAN.objects.restrict(request.user, 'view').filter(site=instance), 'site_id'),
|
|
||||||
# Circuits
|
|
||||||
(Circuit.objects.restrict(request.user, 'view').filter(terminations__site=instance).distinct(), 'site_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(
|
||||||
|
request,
|
||||||
|
instance,
|
||||||
|
[CableTermination, CircuitTermination],
|
||||||
|
(
|
||||||
|
(VLANGroup.objects.restrict(request.user, 'view').filter(
|
||||||
|
scope_type=ContentType.objects.get_for_model(Site),
|
||||||
|
scope_id=instance.pk
|
||||||
|
), 'site'),
|
||||||
|
(ASN.objects.restrict(request.user, 'view').filter(sites=instance), 'site_id'),
|
||||||
|
(Circuit.objects.restrict(request.user, 'view').filter(terminations__site=instance).distinct(),
|
||||||
|
'site_id'),
|
||||||
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -466,18 +466,13 @@ class LocationListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(Location)
|
@register_model_view(Location)
|
||||||
class LocationView(generic.ObjectView):
|
class LocationView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Location.objects.all()
|
queryset = Location.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
locations = instance.get_descendants(include_self=True)
|
locations = instance.get_descendants(include_self=True)
|
||||||
related_models = (
|
|
||||||
(Rack.objects.restrict(request.user, 'view').filter(location__in=locations), 'location_id'),
|
|
||||||
(Device.objects.restrict(request.user, 'view').filter(location__in=locations), 'location_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, locations, [CableTermination]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -541,16 +536,12 @@ class RackRoleListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(RackRole)
|
@register_model_view(RackRole)
|
||||||
class RackRoleView(generic.ObjectView):
|
class RackRoleView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = RackRole.objects.all()
|
queryset = RackRole.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Rack.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -655,15 +646,10 @@ class RackElevationListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(Rack)
|
@register_model_view(Rack)
|
||||||
class RackView(generic.ObjectView):
|
class RackView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Rack.objects.prefetch_related('site__region', 'tenant__group', 'location', 'role')
|
queryset = Rack.objects.prefetch_related('site__region', 'tenant__group', 'location', 'role')
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Device.objects.restrict(request.user, 'view').filter(rack=instance), 'rack_id'),
|
|
||||||
(PowerFeed.objects.restrict(request.user).filter(rack=instance), 'rack_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
peer_racks = Rack.objects.restrict(request.user, 'view').filter(site=instance.site)
|
peer_racks = Rack.objects.restrict(request.user, 'view').filter(site=instance.site)
|
||||||
|
|
||||||
if instance.location:
|
if instance.location:
|
||||||
@ -679,7 +665,7 @@ class RackView(generic.ObjectView):
|
|||||||
])
|
])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance, [CableTermination]),
|
||||||
'next_rack': next_rack,
|
'next_rack': next_rack,
|
||||||
'prev_rack': prev_rack,
|
'prev_rack': prev_rack,
|
||||||
'svg_extra': svg_extra,
|
'svg_extra': svg_extra,
|
||||||
@ -838,19 +824,12 @@ class ManufacturerListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(Manufacturer)
|
@register_model_view(Manufacturer)
|
||||||
class ManufacturerView(generic.ObjectView):
|
class ManufacturerView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Manufacturer.objects.all()
|
queryset = Manufacturer.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, 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 {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance, [InventoryItemTemplate]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -912,16 +891,16 @@ class DeviceTypeListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(DeviceType)
|
@register_model_view(DeviceType)
|
||||||
class DeviceTypeView(generic.ObjectView):
|
class DeviceTypeView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = DeviceType.objects.all()
|
queryset = DeviceType.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Device.objects.restrict(request.user).filter(device_type=instance), 'device_type_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance, omit=[
|
||||||
|
ConsolePortTemplate, ConsoleServerPortTemplate, DeviceBayTemplate, FrontPortTemplate,
|
||||||
|
InventoryItemTemplate, InterfaceTemplate, ModuleBayTemplate, PowerOutletTemplate, PowerPortTemplate,
|
||||||
|
RearPortTemplate,
|
||||||
|
]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1151,16 +1130,16 @@ class ModuleTypeListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(ModuleType)
|
@register_model_view(ModuleType)
|
||||||
class ModuleTypeView(generic.ObjectView):
|
class ModuleTypeView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = ModuleType.objects.all()
|
queryset = ModuleType.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Module.objects.restrict(request.user).filter(module_type=instance), 'module_type_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance, omit=[
|
||||||
|
ConsolePortTemplate, ConsoleServerPortTemplate, DeviceBayTemplate, FrontPortTemplate,
|
||||||
|
InventoryItemTemplate, InterfaceTemplate, ModuleBayTemplate, PowerOutletTemplate, PowerPortTemplate,
|
||||||
|
RearPortTemplate,
|
||||||
|
]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1711,17 +1690,12 @@ class DeviceRoleListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(DeviceRole)
|
@register_model_view(DeviceRole)
|
||||||
class DeviceRoleView(generic.ObjectView):
|
class DeviceRoleView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = DeviceRole.objects.all()
|
queryset = DeviceRole.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Device.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
|
|
||||||
(VirtualMachine.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1775,17 +1749,12 @@ class PlatformListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(Platform)
|
@register_model_view(Platform)
|
||||||
class PlatformView(generic.ObjectView):
|
class PlatformView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Platform.objects.all()
|
queryset = Platform.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, 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 {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2157,22 +2126,12 @@ class ModuleListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(Module)
|
@register_model_view(Module)
|
||||||
class ModuleView(generic.ObjectView):
|
class ModuleView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Module.objects.all()
|
queryset = Module.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Interface.objects.restrict(request.user, 'view').filter(module=instance), 'module_id'),
|
|
||||||
(ConsolePort.objects.restrict(request.user, 'view').filter(module=instance), 'module_id'),
|
|
||||||
(ConsoleServerPort.objects.restrict(request.user, 'view').filter(module=instance), 'module_id'),
|
|
||||||
(PowerPort.objects.restrict(request.user, 'view').filter(module=instance), 'module_id'),
|
|
||||||
(PowerOutlet.objects.restrict(request.user, 'view').filter(module=instance), 'module_id'),
|
|
||||||
(FrontPort.objects.restrict(request.user, 'view').filter(module=instance), 'module_id'),
|
|
||||||
(RearPort.objects.restrict(request.user, 'view').filter(module=instance), 'module_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3552,16 +3511,12 @@ class PowerPanelListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(PowerPanel)
|
@register_model_view(PowerPanel)
|
||||||
class PowerPanelView(generic.ObjectView):
|
class PowerPanelView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = PowerPanel.objects.all()
|
queryset = PowerPanel.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(PowerFeed.objects.restrict(request.user).filter(power_panel=instance), 'power_panel_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3665,16 +3620,18 @@ class VirtualDeviceContextListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(VirtualDeviceContext)
|
@register_model_view(VirtualDeviceContext)
|
||||||
class VirtualDeviceContextView(generic.ObjectView):
|
class VirtualDeviceContextView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = VirtualDeviceContext.objects.all()
|
queryset = VirtualDeviceContext.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Interface.objects.restrict(request.user, 'view').filter(vdcs__in=[instance]), 'vdc_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(
|
||||||
|
request,
|
||||||
|
instance,
|
||||||
|
extra=(
|
||||||
|
(Interface.objects.restrict(request.user, 'view').filter(vdcs__in=[instance]), 'vdc_id'),
|
||||||
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ from netbox.views import generic
|
|||||||
from tenancy.views import ObjectContactsView
|
from tenancy.views import ObjectContactsView
|
||||||
from utilities.query import count_related
|
from utilities.query import count_related
|
||||||
from utilities.tables import get_table_ordering
|
from utilities.tables import get_table_ordering
|
||||||
from utilities.views import ViewTab, register_model_view
|
from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
|
||||||
from virtualization.filtersets import VMInterfaceFilterSet
|
from virtualization.filtersets import VMInterfaceFilterSet
|
||||||
from virtualization.models import VMInterface
|
from virtualization.models import VMInterface
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
@ -34,15 +34,10 @@ class VRFListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(VRF)
|
@register_model_view(VRF)
|
||||||
class VRFView(generic.ObjectView):
|
class VRFView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = VRF.objects.all()
|
queryset = VRF.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Prefix.objects.restrict(request.user, 'view').filter(vrf=instance), 'vrf_id'),
|
|
||||||
(IPAddress.objects.restrict(request.user, 'view').filter(vrf=instance), 'vrf_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
import_targets_table = tables.RouteTargetTable(
|
import_targets_table = tables.RouteTargetTable(
|
||||||
instance.import_targets.all(),
|
instance.import_targets.all(),
|
||||||
orderable=False
|
orderable=False
|
||||||
@ -53,7 +48,7 @@ class VRFView(generic.ObjectView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance, omit=[Interface, VMInterface]),
|
||||||
'import_targets_table': import_targets_table,
|
'import_targets_table': import_targets_table,
|
||||||
'export_targets_table': export_targets_table,
|
'export_targets_table': export_targets_table,
|
||||||
}
|
}
|
||||||
@ -147,16 +142,12 @@ class RIRListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(RIR)
|
@register_model_view(RIR)
|
||||||
class RIRView(generic.ObjectView):
|
class RIRView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = RIR.objects.all()
|
queryset = RIR.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Aggregate.objects.restrict(request.user, 'view').filter(rir=instance), 'rir_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -273,17 +264,19 @@ class ASNListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(ASN)
|
@register_model_view(ASN)
|
||||||
class ASNView(generic.ObjectView):
|
class ASNView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = ASN.objects.all()
|
queryset = ASN.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Site.objects.restrict(request.user, 'view').filter(asns__in=[instance]), 'asn_id'),
|
|
||||||
(Provider.objects.restrict(request.user, 'view').filter(asns__in=[instance]), 'asn_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(
|
||||||
|
request,
|
||||||
|
instance,
|
||||||
|
extra=(
|
||||||
|
(Site.objects.restrict(request.user, 'view').filter(asns__in=[instance]), 'asn_id'),
|
||||||
|
(Provider.objects.restrict(request.user, 'view').filter(asns__in=[instance]), 'asn_id'),
|
||||||
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -427,18 +420,12 @@ class RoleListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(Role)
|
@register_model_view(Role)
|
||||||
class RoleView(generic.ObjectView):
|
class RoleView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Role.objects.all()
|
queryset = Role.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
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 {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -926,16 +913,12 @@ class VLANGroupListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(VLANGroup)
|
@register_model_view(VLANGroup)
|
||||||
class VLANGroupView(generic.ObjectView):
|
class VLANGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
|
queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(VLAN.objects.restrict(request.user, 'view').filter(group=instance), 'group_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,8 +4,7 @@ from django.utils.translation import gettext as _
|
|||||||
|
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
from utilities.query import count_related
|
from utilities.query import count_related
|
||||||
from utilities.relations import get_related_models
|
from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
|
||||||
from utilities.views import register_model_view, ViewTab
|
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
@ -56,17 +55,14 @@ class TenantGroupListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(TenantGroup)
|
@register_model_view(TenantGroup)
|
||||||
class TenantGroupView(generic.ObjectView):
|
class TenantGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = TenantGroup.objects.all()
|
queryset = TenantGroup.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
groups = instance.get_descendants(include_self=True)
|
groups = instance.get_descendants(include_self=True)
|
||||||
related_models = (
|
|
||||||
(Tenant.objects.restrict(request.user, 'view').filter(group__in=groups), 'group_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, groups),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -123,17 +119,12 @@ class TenantListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(Tenant)
|
@register_model_view(Tenant)
|
||||||
class TenantView(generic.ObjectView):
|
class TenantView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Tenant.objects.all()
|
queryset = Tenant.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = [
|
|
||||||
(model.objects.restrict(request.user, 'view').filter(tenant=instance), f'{field}_id')
|
|
||||||
for model, field in get_related_models(Tenant)
|
|
||||||
]
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -189,17 +180,14 @@ class ContactGroupListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(ContactGroup)
|
@register_model_view(ContactGroup)
|
||||||
class ContactGroupView(generic.ObjectView):
|
class ContactGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = ContactGroup.objects.all()
|
queryset = ContactGroup.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
groups = instance.get_descendants(include_self=True)
|
groups = instance.get_descendants(include_self=True)
|
||||||
related_models = (
|
|
||||||
(Contact.objects.restrict(request.user, 'view').filter(group__in=groups), 'group_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, groups),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -256,16 +244,12 @@ class ContactRoleListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(ContactRole)
|
@register_model_view(ContactRole)
|
||||||
class ContactRoleView(generic.ObjectView):
|
class ContactRoleView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = ContactRole.objects.all()
|
queryset = ContactRole.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(ContactAssignment.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from typing import Iterable
|
||||||
|
|
||||||
from django.contrib.auth.mixins import AccessMixin
|
from django.contrib.auth.mixins import AccessMixin
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@ -6,10 +8,12 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
from netbox.plugins import PluginConfig
|
from netbox.plugins import PluginConfig
|
||||||
from netbox.registry import registry
|
from netbox.registry import registry
|
||||||
|
from utilities.relations import get_related_models
|
||||||
from .permissions import resolve_permission
|
from .permissions import resolve_permission
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ContentTypePermissionRequiredMixin',
|
'ContentTypePermissionRequiredMixin',
|
||||||
|
'GetRelatedModelsMixin',
|
||||||
'GetReturnURLMixin',
|
'GetReturnURLMixin',
|
||||||
'ObjectPermissionRequiredMixin',
|
'ObjectPermissionRequiredMixin',
|
||||||
'ViewTab',
|
'ViewTab',
|
||||||
@ -142,6 +146,46 @@ class GetReturnURLMixin:
|
|||||||
return reverse('home')
|
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:
|
class ViewTab:
|
||||||
"""
|
"""
|
||||||
ViewTabs are used for navigation among multiple object-specific views, such as the changelog or journal for
|
ViewTabs are used for navigation among multiple object-specific views, such as the changelog or journal for
|
||||||
|
@ -20,7 +20,7 @@ from netbox.views import generic
|
|||||||
from tenancy.views import ObjectContactsView
|
from tenancy.views import ObjectContactsView
|
||||||
from utilities.query import count_related
|
from utilities.query import count_related
|
||||||
from utilities.query_functions import CollateAsChar
|
from utilities.query_functions import CollateAsChar
|
||||||
from utilities.views import ViewTab, register_model_view
|
from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
@ -39,16 +39,12 @@ class ClusterTypeListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(ClusterType)
|
@register_model_view(ClusterType)
|
||||||
class ClusterTypeView(generic.ObjectView):
|
class ClusterTypeView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = ClusterType.objects.all()
|
queryset = ClusterType.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Cluster.objects.restrict(request.user, 'view').filter(type=instance), 'type_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -99,16 +95,12 @@ class ClusterGroupListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(ClusterGroup)
|
@register_model_view(ClusterGroup)
|
||||||
class ClusterGroupView(generic.ObjectView):
|
class ClusterGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = ClusterGroup.objects.all()
|
queryset = ClusterGroup.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Cluster.objects.restrict(request.user, 'view').filter(group=instance), 'group_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ from ipam.tables import RouteTargetTable
|
|||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
from tenancy.views import ObjectContactsView
|
from tenancy.views import ObjectContactsView
|
||||||
from utilities.query import count_related
|
from utilities.query import count_related
|
||||||
from utilities.views import register_model_view
|
from utilities.views import GetRelatedModelsMixin, register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
@ -21,16 +21,12 @@ class TunnelGroupListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(TunnelGroup)
|
@register_model_view(TunnelGroup)
|
||||||
class TunnelGroupView(generic.ObjectView):
|
class TunnelGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = TunnelGroup.objects.all()
|
queryset = TunnelGroup.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_models = (
|
|
||||||
(Tunnel.objects.restrict(request.user, 'view').filter(group=instance), 'group_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, instance),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from dcim.models import Interface
|
from dcim.models import Interface
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
from utilities.query import count_related
|
from utilities.query import count_related
|
||||||
from utilities.views import register_model_view
|
from utilities.views import GetRelatedModelsMixin, register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
@ -24,17 +24,14 @@ class WirelessLANGroupListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(WirelessLANGroup)
|
@register_model_view(WirelessLANGroup)
|
||||||
class WirelessLANGroupView(generic.ObjectView):
|
class WirelessLANGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = WirelessLANGroup.objects.all()
|
queryset = WirelessLANGroup.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
groups = instance.get_descendants(include_self=True)
|
groups = instance.get_descendants(include_self=True)
|
||||||
related_models = (
|
|
||||||
(WirelessLAN.objects.restrict(request.user, 'view').filter(group__in=groups), 'group_id'),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'related_models': related_models,
|
'related_models': self.get_related_models(request, groups),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user