mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-22 20:12:00 -06:00
Add dedicated views for nested group models
This commit is contained in:
parent
b7e44a744d
commit
2820d26a0f
@ -56,7 +56,7 @@ class Region(NestedGroupModel):
|
||||
csv_headers = ['name', 'slug', 'parent', 'description']
|
||||
|
||||
def get_absolute_url(self):
|
||||
return "{}?region={}".format(reverse('dcim:site_list'), self.slug)
|
||||
return reverse('dcim:region', args=[self.pk])
|
||||
|
||||
def to_csv(self):
|
||||
return (
|
||||
@ -108,7 +108,7 @@ class SiteGroup(NestedGroupModel):
|
||||
csv_headers = ['name', 'slug', 'parent', 'description']
|
||||
|
||||
def get_absolute_url(self):
|
||||
return "{}?group={}".format(reverse('dcim:site_list'), self.slug)
|
||||
return reverse('dcim:sitegroup', args=[self.pk])
|
||||
|
||||
def to_csv(self):
|
||||
return (
|
||||
@ -324,7 +324,7 @@ class Location(NestedGroupModel):
|
||||
]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return "{}?location_id={}".format(reverse('dcim:rack_list'), self.pk)
|
||||
return reverse('dcim:location', args=[self.pk])
|
||||
|
||||
def to_csv(self):
|
||||
return (
|
||||
|
@ -19,12 +19,14 @@ __all__ = (
|
||||
|
||||
|
||||
#
|
||||
# Rack groups
|
||||
# Locations
|
||||
#
|
||||
|
||||
class LocationTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = MPTTColumn()
|
||||
name = MPTTColumn(
|
||||
linkify=True
|
||||
)
|
||||
site = tables.Column(
|
||||
linkify=True
|
||||
)
|
||||
|
@ -17,7 +17,9 @@ __all__ = (
|
||||
|
||||
class RegionTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = MPTTColumn()
|
||||
name = MPTTColumn(
|
||||
linkify=True
|
||||
)
|
||||
site_count = tables.Column(
|
||||
verbose_name='Sites'
|
||||
)
|
||||
@ -35,7 +37,9 @@ class RegionTable(BaseTable):
|
||||
|
||||
class SiteGroupTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = MPTTColumn()
|
||||
name = MPTTColumn(
|
||||
linkify=True
|
||||
)
|
||||
site_count = tables.Column(
|
||||
verbose_name='Sites'
|
||||
)
|
||||
|
@ -14,6 +14,7 @@ urlpatterns = [
|
||||
path('regions/import/', views.RegionBulkImportView.as_view(), name='region_import'),
|
||||
path('regions/edit/', views.RegionBulkEditView.as_view(), name='region_bulk_edit'),
|
||||
path('regions/delete/', views.RegionBulkDeleteView.as_view(), name='region_bulk_delete'),
|
||||
path('regions/<int:pk>/', views.RegionView.as_view(), name='region'),
|
||||
path('regions/<int:pk>/edit/', views.RegionEditView.as_view(), name='region_edit'),
|
||||
path('regions/<int:pk>/delete/', views.RegionDeleteView.as_view(), name='region_delete'),
|
||||
path('regions/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='region_changelog', kwargs={'model': Region}),
|
||||
@ -24,6 +25,7 @@ urlpatterns = [
|
||||
path('site-groups/import/', views.SiteGroupBulkImportView.as_view(), name='sitegroup_import'),
|
||||
path('site-groups/edit/', views.SiteGroupBulkEditView.as_view(), name='sitegroup_bulk_edit'),
|
||||
path('site-groups/delete/', views.SiteGroupBulkDeleteView.as_view(), name='sitegroup_bulk_delete'),
|
||||
path('site-groups/<int:pk>/', views.SiteGroupView.as_view(), name='sitegroup'),
|
||||
path('site-groups/<int:pk>/edit/', views.SiteGroupEditView.as_view(), name='sitegroup_edit'),
|
||||
path('site-groups/<int:pk>/delete/', views.SiteGroupDeleteView.as_view(), name='sitegroup_delete'),
|
||||
path('site-groups/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='sitegroup_changelog', kwargs={'model': SiteGroup}),
|
||||
@ -47,6 +49,7 @@ urlpatterns = [
|
||||
path('locations/import/', views.LocationBulkImportView.as_view(), name='location_import'),
|
||||
path('locations/edit/', views.LocationBulkEditView.as_view(), name='location_bulk_edit'),
|
||||
path('locations/delete/', views.LocationBulkDeleteView.as_view(), name='location_bulk_delete'),
|
||||
path('locations/<int:pk>/', views.LocationView.as_view(), name='location'),
|
||||
path('locations/<int:pk>/edit/', views.LocationEditView.as_view(), name='location_edit'),
|
||||
path('locations/<int:pk>/delete/', views.LocationDeleteView.as_view(), name='location_delete'),
|
||||
path('locations/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='location_changelog', kwargs={'model': Location}),
|
||||
|
@ -112,6 +112,23 @@ class RegionListView(generic.ObjectListView):
|
||||
table = tables.RegionTable
|
||||
|
||||
|
||||
class RegionView(generic.ObjectView):
|
||||
queryset = Region.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
sites = Site.objects.restrict(request.user, 'view').filter(
|
||||
region=instance
|
||||
)
|
||||
|
||||
sites_table = tables.SiteTable(sites)
|
||||
sites_table.columns.hide('region')
|
||||
paginate_table(sites_table, request)
|
||||
|
||||
return {
|
||||
'sites_table': sites_table,
|
||||
}
|
||||
|
||||
|
||||
class RegionEditView(generic.ObjectEditView):
|
||||
queryset = Region.objects.all()
|
||||
model_form = forms.RegionForm
|
||||
@ -169,6 +186,23 @@ class SiteGroupListView(generic.ObjectListView):
|
||||
table = tables.SiteGroupTable
|
||||
|
||||
|
||||
class SiteGroupView(generic.ObjectView):
|
||||
queryset = SiteGroup.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
sites = Site.objects.restrict(request.user, 'view').filter(
|
||||
group=instance
|
||||
)
|
||||
|
||||
sites_table = tables.SiteTable(sites)
|
||||
sites_table.columns.hide('group')
|
||||
paginate_table(sites_table, request)
|
||||
|
||||
return {
|
||||
'sites_table': sites_table,
|
||||
}
|
||||
|
||||
|
||||
class SiteGroupEditView(generic.ObjectEditView):
|
||||
queryset = SiteGroup.objects.all()
|
||||
model_form = forms.SiteGroupForm
|
||||
@ -291,6 +325,23 @@ class LocationListView(generic.ObjectListView):
|
||||
table = tables.LocationTable
|
||||
|
||||
|
||||
class LocationView(generic.ObjectView):
|
||||
queryset = Location.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
devices = Device.objects.restrict(request.user, 'view').filter(
|
||||
location=instance
|
||||
)
|
||||
|
||||
devices_table = tables.DeviceTable(devices)
|
||||
devices_table.columns.hide('location')
|
||||
paginate_table(devices_table, request)
|
||||
|
||||
return {
|
||||
'devices_table': devices_table,
|
||||
}
|
||||
|
||||
|
||||
class LocationEditView(generic.ObjectEditView):
|
||||
queryset = Location.objects.all()
|
||||
model_form = forms.LocationForm
|
||||
|
73
netbox/templates/dcim/location.html
Normal file
73
netbox/templates/dcim/location.html
Normal file
@ -0,0 +1,73 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load helpers %}
|
||||
{% load plugins %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<li><a href="{% url 'dcim:location_list' %}">Location</a></li>
|
||||
{% for location in object.get_ancestors %}
|
||||
<li><a href="{{ location.get_absolute_url }}">{{ location }}</a></li>
|
||||
{% endfor %}
|
||||
<li>{{ object }}</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<strong>Location</strong>
|
||||
</div>
|
||||
<table class="table table-hover panel-body attr-table">
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Description</td>
|
||||
<td>{{ object.description|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Parent</td>
|
||||
<td>
|
||||
{% if object.parent %}
|
||||
<a href="{{ object.parent.get_absolute_url }}">{{ object.parent }}</a>
|
||||
{% else %}
|
||||
<span class="text-muted">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Devices</td>
|
||||
<td>
|
||||
<a href="{% url 'dcim:device_list' %}?location_id={{ object.pk }}">{{ devices_table.rows|length }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% plugin_left_page object %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{% include 'inc/custom_fields_panel.html' %}
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<strong>Devices</strong>
|
||||
</div>
|
||||
{% include 'inc/table.html' with table=devices_table %}
|
||||
{% if perms.dcim.add_device %}
|
||||
<div class="panel-footer text-right noprint">
|
||||
<a href="{% url 'dcim:device_add' %}?location={{ object.pk }}" class="btn btn-xs btn-primary">
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add device
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% include 'inc/paginator.html' with paginator=devices_table.paginator page=devices_table.page %}
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
73
netbox/templates/dcim/region.html
Normal file
73
netbox/templates/dcim/region.html
Normal file
@ -0,0 +1,73 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load helpers %}
|
||||
{% load plugins %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<li><a href="{% url 'dcim:region_list' %}">Region</a></li>
|
||||
{% for region in object.get_ancestors %}
|
||||
<li><a href="{{ region.get_absolute_url }}">{{ region }}</a></li>
|
||||
{% endfor %}
|
||||
<li>{{ object }}</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<strong>Region</strong>
|
||||
</div>
|
||||
<table class="table table-hover panel-body attr-table">
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Description</td>
|
||||
<td>{{ object.description|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Parent</td>
|
||||
<td>
|
||||
{% if object.parent %}
|
||||
<a href="{{ object.parent.get_absolute_url }}">{{ object.parent }}</a>
|
||||
{% else %}
|
||||
<span class="text-muted">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sites</td>
|
||||
<td>
|
||||
<a href="{% url 'dcim:site_list' %}?region_id={{ object.pk }}">{{ sites_table.rows|length }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% plugin_left_page object %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{% include 'inc/custom_fields_panel.html' %}
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<strong>Sites</strong>
|
||||
</div>
|
||||
{% include 'inc/table.html' with table=sites_table %}
|
||||
{% if perms.dcim.add_site %}
|
||||
<div class="panel-footer text-right noprint">
|
||||
<a href="{% url 'dcim:site_add' %}?region={{ object.pk }}" class="btn btn-xs btn-primary">
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add site
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% include 'inc/paginator.html' with paginator=sites_table.paginator page=sites_table.page %}
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
73
netbox/templates/dcim/sitegroup.html
Normal file
73
netbox/templates/dcim/sitegroup.html
Normal file
@ -0,0 +1,73 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load helpers %}
|
||||
{% load plugins %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<li><a href="{% url 'dcim:sitegroup_list' %}">Site Groups</a></li>
|
||||
{% for sitegroup in object.get_ancestors %}
|
||||
<li><a href="{{ sitegroup.get_absolute_url }}">{{ sitegroup }}</a></li>
|
||||
{% endfor %}
|
||||
<li>{{ object }}</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<strong>Site Group</strong>
|
||||
</div>
|
||||
<table class="table table-hover panel-body attr-table">
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Description</td>
|
||||
<td>{{ object.description|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Parent</td>
|
||||
<td>
|
||||
{% if object.parent %}
|
||||
<a href="{{ object.parent.get_absolute_url }}">{{ object.parent }}</a>
|
||||
{% else %}
|
||||
<span class="text-muted">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sites</td>
|
||||
<td>
|
||||
<a href="{% url 'dcim:site_list' %}?group_id={{ object.pk }}">{{ sites_table.rows|length }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% plugin_left_page object %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{% include 'inc/custom_fields_panel.html' %}
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<strong>Sites</strong>
|
||||
</div>
|
||||
{% include 'inc/table.html' with table=sites_table %}
|
||||
{% if perms.dcim.add_site %}
|
||||
<div class="panel-footer text-right noprint">
|
||||
<a href="{% url 'dcim:site_add' %}?group={{ object.pk }}" class="btn btn-xs btn-primary">
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add site
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% include 'inc/paginator.html' with paginator=sites_table.paginator page=sites_table.page %}
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
73
netbox/templates/tenancy/tenantgroup.html
Normal file
73
netbox/templates/tenancy/tenantgroup.html
Normal file
@ -0,0 +1,73 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load helpers %}
|
||||
{% load plugins %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<li><a href="{% url 'tenancy:tenantgroup_list' %}">Tenant Groups</a></li>
|
||||
{% for tenantgroup in object.get_ancestors %}
|
||||
<li><a href="{{ tenantgroup.get_absolute_url }}">{{ tenantgroup }}</a></li>
|
||||
{% endfor %}
|
||||
<li>{{ object }}</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<strong>Tenant Group</strong>
|
||||
</div>
|
||||
<table class="table table-hover panel-body attr-table">
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Description</td>
|
||||
<td>{{ object.description|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Parent</td>
|
||||
<td>
|
||||
{% if object.parent %}
|
||||
<a href="{{ object.parent.get_absolute_url }}">{{ object.parent }}</a>
|
||||
{% else %}
|
||||
<span class="text-muted">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sites</td>
|
||||
<td>
|
||||
<a href="{% url 'tenancy:tenant_list' %}?group_id={{ object.pk }}">{{ tenants_table.rows|length }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% plugin_left_page object %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{% include 'inc/custom_fields_panel.html' %}
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<strong>Tenants</strong>
|
||||
</div>
|
||||
{% include 'inc/table.html' with table=tenants_table %}
|
||||
{% if perms.tenancy.add_tenant %}
|
||||
<div class="panel-footer text-right noprint">
|
||||
<a href="{% url 'tenancy:tenant_add' %}?group={{ object.pk }}" class="btn btn-xs btn-primary">
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add tenant
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% include 'inc/paginator.html' with paginator=tenants_table.paginator page=tenants_table.page %}
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -45,7 +45,7 @@ class TenantGroup(NestedGroupModel):
|
||||
ordering = ['name']
|
||||
|
||||
def get_absolute_url(self):
|
||||
return "{}?group={}".format(reverse('tenancy:tenant_list'), self.slug)
|
||||
return reverse('tenancy:tenantgroup', args=[self.pk])
|
||||
|
||||
def to_csv(self):
|
||||
return (
|
||||
|
@ -35,7 +35,9 @@ class TenantColumn(tables.TemplateColumn):
|
||||
|
||||
class TenantGroupTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = MPTTColumn()
|
||||
name = MPTTColumn(
|
||||
linkify=True
|
||||
)
|
||||
tenant_count = LinkedCountColumn(
|
||||
viewname='tenancy:tenant_list',
|
||||
url_params={'group': 'slug'},
|
||||
|
@ -13,6 +13,7 @@ urlpatterns = [
|
||||
path('tenant-groups/import/', views.TenantGroupBulkImportView.as_view(), name='tenantgroup_import'),
|
||||
path('tenant-groups/edit/', views.TenantGroupBulkEditView.as_view(), name='tenantgroup_bulk_edit'),
|
||||
path('tenant-groups/delete/', views.TenantGroupBulkDeleteView.as_view(), name='tenantgroup_bulk_delete'),
|
||||
path('tenant-groups/<int:pk>/', views.TenantGroupView.as_view(), name='tenantgroup'),
|
||||
path('tenant-groups/<int:pk>/edit/', views.TenantGroupEditView.as_view(), name='tenantgroup_edit'),
|
||||
path('tenant-groups/<int:pk>/delete/', views.TenantGroupDeleteView.as_view(), name='tenantgroup_delete'),
|
||||
path('tenant-groups/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='tenantgroup_changelog', kwargs={'model': TenantGroup}),
|
||||
|
@ -1,9 +1,8 @@
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
|
||||
from circuits.models import Circuit
|
||||
from dcim.models import Site, Rack, Device, RackReservation
|
||||
from ipam.models import IPAddress, Prefix, VLAN, VRF
|
||||
from netbox.views import generic
|
||||
from utilities.tables import paginate_table
|
||||
from virtualization.models import VirtualMachine, Cluster
|
||||
from . import filters, forms, tables
|
||||
from .models import Tenant, TenantGroup
|
||||
@ -24,6 +23,23 @@ class TenantGroupListView(generic.ObjectListView):
|
||||
table = tables.TenantGroupTable
|
||||
|
||||
|
||||
class TenantGroupView(generic.ObjectView):
|
||||
queryset = TenantGroup.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
tenants = Tenant.objects.restrict(request.user, 'view').filter(
|
||||
group=instance
|
||||
)
|
||||
|
||||
tenants_table = tables.TenantTable(tenants)
|
||||
tenants_table.columns.hide('group')
|
||||
paginate_table(tenants_table, request)
|
||||
|
||||
return {
|
||||
'tenants_table': tenants_table,
|
||||
}
|
||||
|
||||
|
||||
class TenantGroupEditView(generic.ObjectEditView):
|
||||
queryset = TenantGroup.objects.all()
|
||||
model_form = forms.TenantGroupForm
|
||||
|
Loading…
Reference in New Issue
Block a user