Standardize related model display for organizational models

This commit is contained in:
jeremystretch 2023-01-25 16:01:10 -05:00 committed by jeremystretch
parent 91b81d51da
commit 94797bb956
16 changed files with 91 additions and 260 deletions

View File

@ -127,6 +127,15 @@ class CircuitTypeListView(generic.ObjectListView):
class CircuitTypeView(generic.ObjectView): class CircuitTypeView(generic.ObjectView):
queryset = CircuitType.objects.all() queryset = CircuitType.objects.all()
def get_extra_context(self, request, instance):
related_models = (
(Circuit.objects.restrict(request.user, 'view').filter(type=instance), 'type_id'),
)
return {
'related_models': related_models,
}
@register_model_view(CircuitType, 'edit') @register_model_view(CircuitType, 'edit')
class CircuitTypeEditView(generic.ObjectEditView): class CircuitTypeEditView(generic.ObjectEditView):

View File

@ -543,6 +543,15 @@ class RackRoleListView(generic.ObjectListView):
class RackRoleView(generic.ObjectView): class RackRoleView(generic.ObjectView):
queryset = RackRole.objects.all() queryset = RackRole.objects.all()
def get_extra_context(self, request, instance):
related_models = (
(Rack.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
)
return {
'related_models': related_models,
}
@register_model_view(RackRole, 'edit') @register_model_view(RackRole, 'edit')
class RackRoleEditView(generic.ObjectEditView): class RackRoleEditView(generic.ObjectEditView):
@ -803,20 +812,15 @@ class ManufacturerView(generic.ObjectView):
queryset = Manufacturer.objects.all() queryset = Manufacturer.objects.all()
def get_extra_context(self, request, instance): def get_extra_context(self, request, instance):
device_types = DeviceType.objects.restrict(request.user, 'view').filter( related_models = (
manufacturer=instance (DeviceType.objects.restrict(request.user, 'view').filter(manufacturer=instance), 'manufacturer_id'),
) (ModuleType.objects.restrict(request.user, 'view').filter(manufacturer=instance), 'manufacturer_id'),
module_types = ModuleType.objects.restrict(request.user, 'view').filter( (InventoryItem.objects.restrict(request.user, 'view').filter(manufacturer=instance), 'manufacturer_id'),
manufacturer=instance (Platform.objects.restrict(request.user, 'view').filter(manufacturer=instance), 'manufacturer_id'),
)
inventory_items = InventoryItem.objects.restrict(request.user, 'view').filter(
manufacturer=instance
) )
return { return {
'devicetype_count': device_types.count(), 'related_models': related_models,
'inventoryitem_count': inventory_items.count(),
'moduletype_count': module_types.count(),
} }
@ -1667,41 +1671,15 @@ class DeviceRoleListView(generic.ObjectListView):
class DeviceRoleView(generic.ObjectView): class DeviceRoleView(generic.ObjectView):
queryset = DeviceRole.objects.all() queryset = DeviceRole.objects.all()
def get_extra_context(self, request, instance):
@register_model_view(DeviceRole, 'devices', path='devices') related_models = (
class DeviceRoleDevicesView(generic.ObjectChildrenView): (Device.objects.restrict(request.user, 'view').filter(device_role=instance), 'role_id'),
queryset = DeviceRole.objects.all() (VirtualMachine.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
child_model = Device
table = tables.DeviceTable
filterset = filtersets.DeviceFilterSet
template_name = 'dcim/devicerole/devices.html'
tab = ViewTab(
label=_('Devices'),
badge=lambda obj: obj.devices.count(),
permission='dcim.view_device',
weight=400
) )
def get_children(self, request, parent): return {
return Device.objects.restrict(request.user, 'view').filter(device_role=parent) 'related_models': related_models,
}
@register_model_view(DeviceRole, 'virtual_machines', path='virtual-machines')
class DeviceRoleVirtualMachinesView(generic.ObjectChildrenView):
queryset = DeviceRole.objects.all()
child_model = VirtualMachine
table = VirtualMachineTable
filterset = VirtualMachineFilterSet
template_name = 'dcim/devicerole/virtual_machines.html'
tab = ViewTab(
label=_('Virtual machines'),
badge=lambda obj: obj.virtual_machines.count(),
permission='virtualization.view_virtualmachine',
weight=500
)
def get_children(self, request, parent):
return VirtualMachine.objects.restrict(request.user, 'view').filter(role=parent)
@register_model_view(DeviceRole, 'edit') @register_model_view(DeviceRole, 'edit')
@ -1758,16 +1736,13 @@ class PlatformView(generic.ObjectView):
queryset = Platform.objects.all() queryset = Platform.objects.all()
def get_extra_context(self, request, instance): def get_extra_context(self, request, instance):
devices = Device.objects.restrict(request.user, 'view').filter( related_models = (
platform=instance (Device.objects.restrict(request.user, 'view').filter(platform=instance), 'platform_id'),
) (VirtualMachine.objects.restrict(request.user, 'view').filter(platform=instance), 'platform_id'),
virtual_machines = VirtualMachine.objects.restrict(request.user, 'view').filter(
platform=instance
) )
return { return {
'device_count': devices.count(), 'related_models': related_models,
'virtualmachine_count': virtual_machines.count()
} }

View File

@ -165,6 +165,15 @@ class RIRListView(generic.ObjectListView):
class RIRView(generic.ObjectView): class RIRView(generic.ObjectView):
queryset = RIR.objects.all() queryset = RIR.objects.all()
def get_extra_context(self, request, instance):
related_models = (
(Aggregate.objects.restrict(request.user, 'view').filter(rir=instance), 'rir_id'),
)
return {
'related_models': related_models,
}
@register_model_view(RIR, 'edit') @register_model_view(RIR, 'edit')
class RIREditView(generic.ObjectEditView): class RIREditView(generic.ObjectEditView):
@ -368,6 +377,17 @@ class RoleListView(generic.ObjectListView):
class RoleView(generic.ObjectView): class RoleView(generic.ObjectView):
queryset = Role.objects.all() queryset = Role.objects.all()
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 {
'related_models': related_models,
}
@register_model_view(Role, 'edit') @register_model_view(Role, 'edit')
class RoleEditView(generic.ObjectEditView): class RoleEditView(generic.ObjectEditView):
@ -839,6 +859,11 @@ class VLANGroupView(generic.ObjectView):
queryset = VLANGroup.objects.all() queryset = VLANGroup.objects.all()
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'),
)
# TODO: Replace with embedded table
vlans = VLAN.objects.restrict(request.user, 'view').filter(group=instance).prefetch_related( vlans = VLAN.objects.restrict(request.user, 'view').filter(group=instance).prefetch_related(
Prefetch('prefixes', queryset=Prefix.objects.restrict(request.user)), Prefetch('prefixes', queryset=Prefix.objects.restrict(request.user)),
'tenant', 'site', 'role', 'tenant', 'site', 'role',
@ -852,7 +877,7 @@ class VLANGroupView(generic.ObjectView):
vlans_table.configure(request) vlans_table.configure(request)
return { return {
'vlans_count': vlans_count, 'related_models': related_models,
'vlans_table': vlans_table, 'vlans_table': vlans_table,
} }

View File

@ -28,12 +28,6 @@
<th scope="row">Description</th> <th scope="row">Description</th>
<td>{{ object.description|placeholder }}</td> <td>{{ object.description|placeholder }}</td>
</tr> </tr>
<tr>
<th scope="row">Circuits</th>
<td>
<a href="{% url 'circuits:circuit_list' %}?type_id={{ object.pk }}">{{ object.circuits.count }}</a>
</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
@ -41,19 +35,13 @@
{% plugin_left_page object %} {% plugin_left_page object %}
</div> </div>
<div class="col col-md-6"> <div class="col col-md-6">
{% include 'inc/panels/related_objects.html' %}
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/custom_fields.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="col col-md-12"> <div class="col col-md-12">
<div class="card">
<h5 class="card-header">Circuits</h5>
<div class="card-body htmx-container table-responsive"
hx-get="{% url 'circuits:circuit_list' %}?type_id={{ object.pk }}"
hx-trigger="load"
></div>
</div>
{% plugin_full_width_page object %} {% plugin_full_width_page object %}
</div> </div>
</div> </div>

View File

@ -42,22 +42,6 @@
<th scope="row">VM Role</th> <th scope="row">VM Role</th>
<td>{% checkmark object.vm_role %}</td> <td>{% checkmark object.vm_role %}</td>
</tr> </tr>
<tr>
<th scope="row">Devices</th>
<td>
<a href="{% url 'dcim:device_list' %}?role_id={{ object.pk }}">{{ object.devices.count }}</a>
</td>
</tr>
<tr>
<th>Virtual Machines</th>
<td>
{% if object.vm_role %}
<a href="{% url 'virtualization:virtualmachine_list' %}?role_id={{ object.pk }}">{{ object.virtual_machines.count }}</a>
{% else %}
{{ ''|placeholder }}
{% endif %}
</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
@ -65,6 +49,7 @@
{% plugin_left_page object %} {% plugin_left_page object %}
</div> </div>
<div class="col col-md-6"> <div class="col col-md-6">
{% include 'inc/panels/related_objects.html' %}
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/custom_fields.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
</div> </div>

View File

@ -1,20 +0,0 @@
{% extends 'dcim/devicerole.html' %}
{% load helpers %}
{% load render_table from django_tables2 %}
{% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal='DeviceTable_config' %}
<form method="post">
{% csrf_token %}
<div class="card">
<div class="card-body" id="object_list">
{% include 'htmx/table.html' %}
</div>
</div>
</form>
{% endblock content %}
{% block modals %}
{{ block.super }}
{% table_config_form table %}
{% endblock modals %}

View File

@ -1,20 +0,0 @@
{% extends 'dcim/devicerole.html' %}
{% load helpers %}
{% load render_table from django_tables2 %}
{% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal='VirtualMachineTable_config' %}
<form method="post">
{% csrf_token %}
<div class="card">
<div class="card-body" id="object_list">
{% include 'htmx/table.html' %}
</div>
</div>
</form>
{% endblock content %}
{% block modals %}
{{ block.super }}
{% table_config_form table %}
{% endblock modals %}

View File

@ -42,24 +42,6 @@
<th scope="row">Description</th> <th scope="row">Description</th>
<td>{{ object.description|placeholder }}</td> <td>{{ object.description|placeholder }}</td>
</tr> </tr>
<tr>
<th scope="row">Device types</th>
<td>
<a href="{% url 'dcim:devicetype_list' %}?manufacturer_id={{ object.pk }}">{{ devicetype_count }}</a>
</td>
</tr>
<tr>
<th scope="row">Module types</th>
<td>
<a href="{% url 'dcim:moduletype_list' %}?manufacturer_id={{ object.pk }}">{{ moduletype_count }}</a>
</td>
</tr>
<tr>
<th scope="row">Inventory Items</th>
<td>
<a href="{% url 'dcim:inventoryitem_list' %}?manufacturer_id={{ object.pk }}">{{ inventoryitem_count }}</a>
</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
@ -67,6 +49,7 @@
{% plugin_left_page object %} {% plugin_left_page object %}
</div> </div>
<div class="col col-md-6"> <div class="col col-md-6">
{% include 'inc/panels/related_objects.html' %}
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/custom_fields.html' %}
{% include 'inc/panels/contacts.html' %} {% include 'inc/panels/contacts.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
@ -74,13 +57,6 @@
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="col col-md-12"> <div class="col col-md-12">
<div class="card">
<h5 class="card-header">Device Types</h5>
<div class="card-body htmx-container table-responsive"
hx-get="{% url 'dcim:devicetype_list' %}?manufacturer_id={{ object.pk }}"
hx-trigger="load"
></div>
</div>
{% plugin_full_width_page object %} {% plugin_full_width_page object %}
</div> </div>
</div> </div>

View File

@ -43,46 +43,26 @@
<th scope="row">NAPALM Driver</th> <th scope="row">NAPALM Driver</th>
<td>{{ object.napalm_driver|placeholder }}</td> <td>{{ object.napalm_driver|placeholder }}</td>
</tr> </tr>
<tr>
<th scope="row">Devices</th>
<td>
<a href="{% url 'dcim:device_list' %}?platform_id={{ object.pk }}">{{ device_count }}</a>
</td>
</tr>
<tr>
<th scope="row">Virtual Machines</th>
<td>
<a href="{% url 'virtualization:virtualmachine_list' %}?platform_id={{ object.pk }}">{{ virtualmachine_count }}</a>
</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
{% include 'inc/panels/tags.html' %} {% include 'inc/panels/tags.html' %}
{% plugin_left_page object %}
</div>
<div class="col col-md-6">
<div class="card"> <div class="card">
<h5 class="card-header"> <h5 class="card-header">NAPALM Arguments</h5>
NAPALM Arguments
</h5>
<div class="card-body"> <div class="card-body">
<pre>{{ object.napalm_args|json }}</pre> <pre>{{ object.napalm_args|json }}</pre>
</div> </div>
</div> </div>
{% plugin_left_page object %}
</div>
<div class="col col-md-6">
{% include 'inc/panels/related_objects.html' %}
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/custom_fields.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="col col-md-12"> <div class="col col-md-12">
<div class="card">
<h5 class="card-header">Devices</h5>
<div class="card-body htmx-container table-responsive"
hx-get="{% url 'dcim:device_list' %}?platform_id={{ object.pk }}"
hx-trigger="load"
></div>
</div>
{% plugin_full_width_page object %} {% plugin_full_width_page object %}
</div> </div>
</div> </div>

View File

@ -34,12 +34,6 @@
<span class="badge color-label" style="background-color: #{{ object.color }}">&nbsp;</span> <span class="badge color-label" style="background-color: #{{ object.color }}">&nbsp;</span>
</td> </td>
</tr> </tr>
<tr>
<th scope="row">Racks</th>
<td>
<a href="{% url 'dcim:rack_list' %}?role_id={{ object.pk }}">{{ object.racks.count }}</a>
</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
@ -47,19 +41,13 @@
{% plugin_left_page object %} {% plugin_left_page object %}
</div> </div>
<div class="col col-md-6"> <div class="col col-md-6">
{% include 'inc/panels/related_objects.html' %}
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/custom_fields.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="col col-md-12"> <div class="col col-md-12">
<div class="card">
<h5 class="card-header">Racks</h5>
<div class="card-body htmx-container table-responsive"
hx-get="{% url 'dcim:rack_list' %}?role_id={{ object.pk }}"
hx-trigger="load"
></div>
</div>
{% plugin_full_width_page object %} {% plugin_full_width_page object %}
</div> </div>
</div> </div>

View File

@ -32,32 +32,20 @@
<th scope="row">Private</th> <th scope="row">Private</th>
<td>{% checkmark object.is_private %}</td> <td>{% checkmark object.is_private %}</td>
</tr> </tr>
<tr>
<th scope="row">Aggregates</th>
<td>
<a href="{% url 'ipam:aggregate_list' %}?rir_id={{ object.pk }}">{{ object.aggregates.count }}</a>
</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
{% include 'inc/panels/tags.html' %}
{% plugin_left_page object %} {% plugin_left_page object %}
</div> </div>
<div class="col col-md-6"> <div class="col col-md-6">
{% include 'inc/panels/tags.html' %} {% include 'inc/panels/related_objects.html' %}
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/custom_fields.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="col col-md-12"> <div class="col col-md-12">
<div class="card">
<h5 class="card-header">Aggregates</h5>
<div class="card-body htmx-container table-responsive"
hx-get="{% url 'ipam:aggregate_list' %}?rir_id={{ object.pk }}"
hx-trigger="load"
></div>
</div>
{% plugin_full_width_page object %} {% plugin_full_width_page object %}
</div> </div>
</div> </div>

View File

@ -32,44 +32,20 @@
<th scope="row">Weight</th> <th scope="row">Weight</th>
<td>{{ object.weight }}</td> <td>{{ object.weight }}</td>
</tr> </tr>
<tr>
<th scope="row">Prefixes</th>
<td>
<a href="{% url 'ipam:prefix_list' %}?role_id={{ object.pk }}">{{ object.prefixes.count }}</a>
</td>
</tr>
<tr>
<th scope="row">IP Ranges</th>
<td>
<a href="{% url 'ipam:iprange_list' %}?role_id={{ object.pk }}">{{ object.ip_ranges.count }}</a>
</td>
</tr>
<tr>
<th scope="row">VLANs</th>
<td>
<a href="{% url 'ipam:vlan_list' %}?role_id={{ object.pk }}">{{ object.vlans.count }}</a>
</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
{% include 'inc/panels/tags.html' %}
{% plugin_left_page object %} {% plugin_left_page object %}
</div> </div>
<div class="col col-md-6"> <div class="col col-md-6">
{% include 'inc/panels/tags.html' %} {% include 'inc/panels/related_objects.html' %}
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/custom_fields.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="col col-md-12"> <div class="col col-md-12">
<div class="card">
<h5 class="card-header">Prefixes</h5>
<div class="card-body htmx-container table-responsive"
hx-get="{% url 'ipam:prefix_list' %}?role_id={{ object.pk }}"
hx-trigger="load"
></div>
</div>
{% plugin_full_width_page object %} {% plugin_full_width_page object %}
</div> </div>
</div> </div>

View File

@ -42,12 +42,6 @@
<th scope="row">Permitted VIDs</th> <th scope="row">Permitted VIDs</th>
<td>{{ object.min_vid }} - {{ object.max_vid }}</td> <td>{{ object.min_vid }} - {{ object.max_vid }}</td>
</tr> </tr>
<tr>
<th scope="row">VLANs</th>
<td>
<a href="{% url 'ipam:vlan_list' %}?group_id={{ object.pk }}">{{ vlans_count }}</a>
</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
@ -55,6 +49,7 @@
{% plugin_left_page object %} {% plugin_left_page object %}
</div> </div>
<div class="col col-md-6"> <div class="col col-md-6">
{% include 'inc/panels/related_objects.html' %}
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/custom_fields.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
</div> </div>

View File

@ -28,12 +28,6 @@
<th scope="row">Description</th> <th scope="row">Description</th>
<td>{{ object.description|placeholder }}</td> <td>{{ object.description|placeholder }}</td>
</tr> </tr>
<tr>
<th scope="row">Clusters</th>
<td>
<a href="{% url 'virtualization:cluster_list' %}?group_id={{ object.pk }}">{{ object.clusters.count }}</a>
</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
@ -41,6 +35,7 @@
{% plugin_left_page object %} {% plugin_left_page object %}
</div> </div>
<div class="col col-md-6"> <div class="col col-md-6">
{% include 'inc/panels/related_objects.html' %}
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/custom_fields.html' %}
{% include 'inc/panels/contacts.html' %} {% include 'inc/panels/contacts.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
@ -48,13 +43,6 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col col-md-12"> <div class="col col-md-12">
<div class="card">
<h5 class="card-header">Clusters</h5>
<div class="card-body htmx-container table-responsive"
hx-get="{% url 'virtualization:cluster_list' %}?group_id={{ object.pk }}"
hx-trigger="load"
></div>
</div>
{% plugin_full_width_page object %} {% plugin_full_width_page object %}
</div> </div>
</div> </div>

View File

@ -41,19 +41,13 @@
{% plugin_left_page object %} {% plugin_left_page object %}
</div> </div>
<div class="col col-md-6"> <div class="col col-md-6">
{% include 'inc/panels/related_objects.html' %}
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/custom_fields.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col col-md-12"> <div class="col col-md-12">
<div class="card">
<h5 class="card-header">Clusters</h5>
<div class="card-body htmx-container table-responsive"
hx-get="{% url 'virtualization:cluster_list' %}?type_id={{ object.pk }}"
hx-trigger="load"
></div>
</div>
{% plugin_full_width_page object %} {% plugin_full_width_page object %}
</div> </div>
</div> </div>

View File

@ -10,7 +10,7 @@ from dcim.models import Device
from dcim.tables import DeviceTable from dcim.tables import DeviceTable
from extras.views import ObjectConfigContextView from extras.views import ObjectConfigContextView
from ipam.models import IPAddress, Service from ipam.models import IPAddress, Service
from ipam.tables import AssignedIPAddressesTable, InterfaceVLANTable from ipam.tables import InterfaceVLANTable
from netbox.views import generic from netbox.views import generic
from utilities.utils import count_related from utilities.utils import count_related
from utilities.views import ViewTab, register_model_view from utilities.views import ViewTab, register_model_view
@ -36,17 +36,12 @@ class ClusterTypeView(generic.ObjectView):
queryset = ClusterType.objects.all() queryset = ClusterType.objects.all()
def get_extra_context(self, request, instance): def get_extra_context(self, request, instance):
clusters = Cluster.objects.restrict(request.user, 'view').filter( related_models = (
type=instance (Cluster.objects.restrict(request.user, 'view').filter(type=instance), 'type_id'),
).annotate(
device_count=count_related(Device, 'cluster'),
vm_count=count_related(VirtualMachine, 'cluster')
) )
clusters_table = tables.ClusterTable(clusters, user=request.user, exclude=('type',))
clusters_table.configure(request)
return { return {
'clusters_table': clusters_table, 'related_models': related_models,
} }
@ -100,6 +95,15 @@ class ClusterGroupListView(generic.ObjectListView):
class ClusterGroupView(generic.ObjectView): class ClusterGroupView(generic.ObjectView):
queryset = ClusterGroup.objects.all() queryset = ClusterGroup.objects.all()
def get_extra_context(self, request, instance):
related_models = (
(Cluster.objects.restrict(request.user, 'view').filter(group=instance), 'group_id'),
)
return {
'related_models': related_models,
}
@register_model_view(ClusterGroup, 'edit') @register_model_view(ClusterGroup, 'edit')
class ClusterGroupEditView(generic.ObjectEditView): class ClusterGroupEditView(generic.ObjectEditView):