mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-18 11:22:25 -06:00
Added virtualization filters
This commit is contained in:
@@ -4,6 +4,7 @@ from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from extras.api.views import CustomFieldModelViewSet
|
||||
from utilities.api import WritableSerializerMixin
|
||||
from virtualization import filters
|
||||
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
|
||||
from . import serializers
|
||||
|
||||
@@ -26,6 +27,7 @@ class ClusterViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
|
||||
queryset = Cluster.objects.select_related('type', 'group')
|
||||
serializer_class = serializers.ClusterSerializer
|
||||
write_serializer_class = serializers.WritableClusterSerializer
|
||||
filter_class = filters.ClusterFilter
|
||||
|
||||
|
||||
#
|
||||
@@ -36,6 +38,7 @@ class VirtualMachineViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
|
||||
queryset = VirtualMachine.objects.all()
|
||||
serializer_class = serializers.VirtualMachineSerializer
|
||||
write_serializer_class = serializers.WritableVirtualMachineSerializer
|
||||
filter_class = filters.VirtualMachineFilter
|
||||
|
||||
|
||||
class VMInterfaceViewSet(WritableSerializerMixin, ModelViewSet):
|
||||
|
||||
99
netbox/virtualization/filters.py
Normal file
99
netbox/virtualization/filters.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django_filters
|
||||
from django.db.models import Q
|
||||
|
||||
from dcim.models import Platform
|
||||
from extras.filters import CustomFieldFilterSet
|
||||
from tenancy.models import Tenant
|
||||
from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
|
||||
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
||||
|
||||
|
||||
class ClusterFilter(CustomFieldFilterSet):
|
||||
id__in = NumericInFilter(name='id', lookup_expr='in')
|
||||
q = django_filters.CharFilter(
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
group_id = NullableModelMultipleChoiceFilter(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
label='Parent group (ID)',
|
||||
)
|
||||
group = NullableModelMultipleChoiceFilter(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Parent group (slug)',
|
||||
)
|
||||
type_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=ClusterType.objects.all(),
|
||||
label='Cluster type (ID)',
|
||||
)
|
||||
type = django_filters.ModelMultipleChoiceFilter(
|
||||
name='type__slug',
|
||||
queryset=ClusterType.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Cluster type (slug)',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Cluster
|
||||
fields = ['name']
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
if not value.strip():
|
||||
return queryset
|
||||
return queryset.filter(
|
||||
Q(name__icontains=value) |
|
||||
Q(comments__icontains=value)
|
||||
)
|
||||
|
||||
|
||||
class VirtualMachineFilter(CustomFieldFilterSet):
|
||||
id__in = NumericInFilter(name='id', lookup_expr='in')
|
||||
q = django_filters.CharFilter(
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
cluster_group_id = NullableModelMultipleChoiceFilter(
|
||||
name='cluster__group',
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
label='Cluster group (ID)',
|
||||
)
|
||||
cluster_group = NullableModelMultipleChoiceFilter(
|
||||
name='cluster__group__slug',
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Cluster group (slug)',
|
||||
)
|
||||
tenant_id = NullableModelMultipleChoiceFilter(
|
||||
queryset=Tenant.objects.all(),
|
||||
label='Tenant (ID)',
|
||||
)
|
||||
tenant = NullableModelMultipleChoiceFilter(
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Tenant (slug)',
|
||||
)
|
||||
platform_id = NullableModelMultipleChoiceFilter(
|
||||
queryset=Platform.objects.all(),
|
||||
label='Platform (ID)',
|
||||
)
|
||||
platform = NullableModelMultipleChoiceFilter(
|
||||
name='platform',
|
||||
queryset=Platform.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Platform (slug)',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = VirtualMachine
|
||||
fields = ['name', 'cluster']
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
if not value.strip():
|
||||
return queryset
|
||||
return queryset.filter(
|
||||
Q(name__icontains=value) |
|
||||
Q(comments__icontains=value)
|
||||
)
|
||||
@@ -1,11 +1,12 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django import forms
|
||||
from django.db.models import Count
|
||||
|
||||
from extras.forms import CustomFieldBulkEditForm, CustomFieldForm
|
||||
from extras.forms import CustomFieldBulkEditForm, CustomFieldForm, CustomFieldFilterForm
|
||||
from tenancy.forms import TenancyForm
|
||||
from tenancy.models import Tenant
|
||||
from utilities.forms import BootstrapMixin, SlugField
|
||||
from utilities.forms import APISelect, BootstrapMixin, ChainedModelChoiceField, FilterChoiceField, SlugField
|
||||
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
||||
|
||||
|
||||
@@ -67,15 +68,58 @@ class ClusterCSVForm(forms.ModelForm):
|
||||
fields = ['name', 'type', 'group']
|
||||
|
||||
|
||||
class ClusterFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
model = Cluster
|
||||
q = forms.CharField(required=False, label='Search')
|
||||
group = FilterChoiceField(
|
||||
queryset=ClusterGroup.objects.annotate(filter_count=Count('clusters')),
|
||||
to_field_name='slug',
|
||||
null_option=(0, 'None'),
|
||||
required=False,
|
||||
)
|
||||
type = FilterChoiceField(
|
||||
queryset=ClusterType.objects.annotate(filter_count=Count('clusters')),
|
||||
to_field_name='slug',
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Virtual Machines
|
||||
#
|
||||
|
||||
class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
cluster_group = forms.ModelChoiceField(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
required=False,
|
||||
widget=forms.Select(
|
||||
attrs={'filter-for': 'cluster', 'nullable': 'true'}
|
||||
)
|
||||
)
|
||||
cluster = ChainedModelChoiceField(
|
||||
queryset=Cluster.objects.all(),
|
||||
chains=(
|
||||
('group', 'cluster_group'),
|
||||
),
|
||||
widget=APISelect(
|
||||
api_url='/api/virtualization/clusters/?group_id={{cluster_group}}'
|
||||
)
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = VirtualMachine
|
||||
fields = ['name', 'cluster', 'tenant', 'platform', 'comments']
|
||||
fields = ['name', 'cluster_group', 'cluster', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
# Initialize helper selector
|
||||
instance = kwargs.get('instance')
|
||||
if instance.pk and instance.cluster is not None:
|
||||
initial = kwargs.get('initial', {}).copy()
|
||||
initial['cluster_group'] = instance.cluster.group
|
||||
kwargs['initial'] = initial
|
||||
|
||||
super(VirtualMachineForm, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class VirtualMachineCSVForm(forms.ModelForm):
|
||||
@@ -89,7 +133,7 @@ class VirtualMachineCSVForm(forms.ModelForm):
|
||||
)
|
||||
|
||||
class Meta:
|
||||
fields = ['cluster', 'name', 'tenant']
|
||||
fields = ['cluster', 'name', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments']
|
||||
|
||||
|
||||
class VirtualMachineBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
||||
@@ -99,3 +143,17 @@ class VirtualMachineBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
||||
|
||||
class Meta:
|
||||
nullable_fields = ['tenant']
|
||||
|
||||
|
||||
class VirtualMachineFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
model = VirtualMachine
|
||||
q = forms.CharField(required=False, label='Search')
|
||||
cluster_group = FilterChoiceField(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_option=(0, 'None'),
|
||||
)
|
||||
cluster_id = FilterChoiceField(
|
||||
queryset=Cluster.objects.annotate(filter_count=Count('virtual_machines')),
|
||||
label='Cluster'
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.4 on 2017-08-16 19:22
|
||||
# Generated by Django 1.11.4 on 2017-08-16 19:27
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import dcim.fields
|
||||
@@ -13,9 +13,9 @@ class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0041_napalm_integration'),
|
||||
('ipam', '0018_remove_service_uniqueness_constraint'),
|
||||
('tenancy', '0003_unicode_literals'),
|
||||
('dcim', '0041_napalm_integration'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
@@ -63,9 +63,9 @@ class Migration(migrations.Migration):
|
||||
('created', models.DateField(auto_now_add=True)),
|
||||
('last_updated', models.DateTimeField(auto_now=True)),
|
||||
('name', models.CharField(max_length=64, unique=True)),
|
||||
('vcpus', models.PositiveSmallIntegerField(blank=True, verbose_name='vCPUs')),
|
||||
('memory', models.PositiveIntegerField(blank=True, verbose_name='Memory (MB)')),
|
||||
('disk', models.PositiveIntegerField(blank=True, verbose_name='Disk (GB)')),
|
||||
('vcpus', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='vCPUs')),
|
||||
('memory', models.PositiveIntegerField(blank=True, null=True, verbose_name='Memory (MB)')),
|
||||
('disk', models.PositiveIntegerField(blank=True, null=True, verbose_name='Disk (GB)')),
|
||||
('comments', models.TextField(blank=True)),
|
||||
('cluster', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='virtual_machines', to='virtualization.Cluster')),
|
||||
('platform', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='virtual_machines', to='dcim.Platform')),
|
||||
|
||||
@@ -161,14 +161,17 @@ class VirtualMachine(CreatedUpdatedModel, CustomFieldModel):
|
||||
)
|
||||
vcpus = models.PositiveSmallIntegerField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='vCPUs'
|
||||
)
|
||||
memory = models.PositiveIntegerField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Memory (MB)'
|
||||
)
|
||||
disk = models.PositiveIntegerField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Disk (GB)'
|
||||
)
|
||||
comments = models.TextField(
|
||||
|
||||
@@ -77,8 +77,9 @@ class ClusterTable(BaseTable):
|
||||
class VirtualMachineTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn()
|
||||
cluster = tables.LinkColumn('virtualization:cluster', args=[Accessor('cluster.pk')])
|
||||
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = VirtualMachine
|
||||
fields = ('pk', 'name', 'tenant')
|
||||
fields = ('pk', 'name', 'cluster', 'tenant', 'vcpus', 'memory', 'disk')
|
||||
|
||||
@@ -11,6 +11,7 @@ from utilities.views import (
|
||||
ObjectDeleteView, ObjectEditView, ObjectListView,
|
||||
)
|
||||
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
|
||||
from . import filters
|
||||
from . import forms
|
||||
from . import tables
|
||||
|
||||
@@ -84,6 +85,8 @@ class ClusterGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
class ClusterListView(ObjectListView):
|
||||
queryset = Cluster.objects.annotate(vm_count=Count('virtual_machines'))
|
||||
table = tables.ClusterTable
|
||||
filter = filters.ClusterFilter
|
||||
filter_form = forms.ClusterFilterForm
|
||||
template_name = 'virtualization/cluster_list.html'
|
||||
|
||||
|
||||
@@ -138,8 +141,8 @@ class ClusterBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
|
||||
class VirtualMachineListView(ObjectListView):
|
||||
queryset = VirtualMachine.objects.select_related('tenant')
|
||||
# filter = filters.VirtualMachineFilter
|
||||
# filter_form = forms.VirtualMachineFilterForm
|
||||
filter = filters.VirtualMachineFilter
|
||||
filter_form = forms.VirtualMachineFilterForm
|
||||
table = tables.VirtualMachineTable
|
||||
template_name = 'virtualization/virtualmachine_list.html'
|
||||
|
||||
@@ -184,7 +187,7 @@ class VirtualMachineBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
permission_required = 'virtualization.change_virtualmachine'
|
||||
cls = VirtualMachine
|
||||
queryset = VirtualMachine.objects.select_related('tenant')
|
||||
# filter = filters.VirtualMachineFilter
|
||||
filter = filters.VirtualMachineFilter
|
||||
table = tables.VirtualMachineTable
|
||||
form = forms.VirtualMachineBulkEditForm
|
||||
default_return_url = 'virtualization:virtualmachine_list'
|
||||
|
||||
Reference in New Issue
Block a user