Virtulization Select2 forms

This commit is contained in:
John Anderson 2019-01-10 17:32:23 -05:00
parent 951e7a68e9
commit 6dcd48fef1
3 changed files with 163 additions and 70 deletions

View File

@ -1,7 +1,6 @@
from Crypto.Cipher import PKCS1_OAEP from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from django import forms from django import forms
from django.db.models import Count
from taggit.forms import TagField from taggit.forms import TagField
from dcim.models import Device from dcim.models import Device
@ -178,9 +177,7 @@ class SecretFilterForm(BootstrapMixin, CustomFieldFilterForm):
label='Search' label='Search'
) )
role = FilterChoiceField( role = FilterChoiceField(
queryset=SecretRole.objects.annotate( queryset=SecretRole.objects.all(),
filter_count=Count('secrets')
),
to_field_name='slug', to_field_name='slug',
widget=APISelectMultiple( widget=APISelectMultiple(
api_url="/api/secrets/secret-roles/", api_url="/api/secrets/secret-roles/",

View File

@ -717,15 +717,17 @@ class ChainedFieldsMixin(forms.BaseForm):
filters_dict = {} filters_dict = {}
for (db_field, parent_field) in field.chains: for (db_field, parent_field) in field.chains:
if self.is_bound and parent_field in self.data: if self.fields[parent_field].widget.attrs.get('nullable'):
filters_dict[db_field] = None
elif self.is_bound and parent_field in self.data and self.data[parent_field]:
filters_dict[db_field] = self.data[parent_field] or None filters_dict[db_field] = self.data[parent_field] or None
elif self.initial.get(parent_field): elif self.initial.get(parent_field):
filters_dict[db_field] = self.initial[parent_field] filters_dict[db_field] = self.initial[parent_field]
elif self.fields[parent_field].widget.attrs.get('nullable'):
filters_dict[db_field] = None
else: else:
break break
print(filters_dict)
if filters_dict: if filters_dict:
field.queryset = field.queryset.filter(**filters_dict) field.queryset = field.queryset.filter(**filters_dict)
elif not self.is_bound and getattr(self, 'instance', None) and hasattr(self.instance, field_name): elif not self.is_bound and getattr(self, 'instance', None) and hasattr(self.instance, field_name):

View File

@ -1,7 +1,5 @@
from django import forms from django import forms
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db.models import Count
from mptt.forms import TreeNodeChoiceField
from taggit.forms import TagField from taggit.forms import TagField
from dcim.constants import IFACE_FF_VIRTUAL, IFACE_MODE_ACCESS, IFACE_MODE_TAGGED_ALL from dcim.constants import IFACE_FF_VIRTUAL, IFACE_MODE_ACCESS, IFACE_MODE_TAGGED_ALL
@ -12,10 +10,10 @@ from ipam.models import IPAddress
from tenancy.forms import TenancyForm from tenancy.forms import TenancyForm
from tenancy.models import Tenant from tenancy.models import Tenant
from utilities.forms import ( from utilities.forms import (
AnnotatedMultipleChoiceField, APISelect, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, add_blank_choice, APISelect, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
ChainedFieldsMixin, ChainedModelChoiceField, ChainedModelMultipleChoiceField, CommentField, ComponentForm, ChainedFieldsMixin, ChainedModelChoiceField, ChainedModelMultipleChoiceField, CommentField, ComponentForm,
ConfirmationForm, CSVChoiceField, ExpandableNameField, FilterChoiceField, FilterTreeNodeMultipleChoiceField, ConfirmationForm, CSVChoiceField, ExpandableNameField, FilterChoiceField, JSONField, SlugField,
JSONField, SlugField, SmallTextarea, add_blank_choice, SmallTextarea, StaticSelect2, StaticSelect2Multiple
) )
from .constants import VM_STATUS_CHOICES from .constants import VM_STATUS_CHOICES
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
@ -92,6 +90,17 @@ class ClusterForm(BootstrapMixin, CustomFieldForm):
fields = [ fields = [
'name', 'type', 'group', 'site', 'comments', 'tags', 'name', 'type', 'group', 'site', 'comments', 'tags',
] ]
widgets = {
'type': APISelect(
api_url="/api/virtualization/cluster-types/"
),
'group': APISelect(
api_url="/api/virtualization/cluster-groups/"
),
'site': APISelect(
api_url="/api/dcim/sites/"
),
}
class ClusterCSVForm(forms.ModelForm): class ClusterCSVForm(forms.ModelForm):
@ -134,15 +143,24 @@ class ClusterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
) )
type = forms.ModelChoiceField( type = forms.ModelChoiceField(
queryset=ClusterType.objects.all(), queryset=ClusterType.objects.all(),
required=False required=False,
widget=APISelect(
api_url="/api/virtualization/cluster-types/"
)
) )
group = forms.ModelChoiceField( group = forms.ModelChoiceField(
queryset=ClusterGroup.objects.all(), queryset=ClusterGroup.objects.all(),
required=False required=False,
widget=APISelect(
api_url="/api/virtualization/cluster-groups/"
)
) )
site = forms.ModelChoiceField( site = forms.ModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
required=False required=False,
widget=APISelect(
api_url="/api/dcim/sites/"
)
) )
comments = CommentField( comments = CommentField(
widget=SmallTextarea() widget=SmallTextarea()
@ -158,37 +176,48 @@ class ClusterFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Cluster model = Cluster
q = forms.CharField(required=False, label='Search') q = forms.CharField(required=False, label='Search')
type = FilterChoiceField( type = FilterChoiceField(
queryset=ClusterType.objects.annotate( queryset=ClusterType.objects.all(),
filter_count=Count('clusters')
),
to_field_name='slug', to_field_name='slug',
required=False, required=False,
widget=APISelectMultiple(
api_url="/api/virtualization/cluster-types/",
value_field='slug',
)
) )
group = FilterChoiceField( group = FilterChoiceField(
queryset=ClusterGroup.objects.annotate( queryset=ClusterGroup.objects.all(),
filter_count=Count('clusters')
),
to_field_name='slug', to_field_name='slug',
null_label='-- None --', null_label='-- None --',
required=False, required=False,
widget=APISelectMultiple(
api_url="/api/virtualization/cluster-groups/",
value_field='slug',
null_option=True,
)
) )
site = FilterChoiceField( site = FilterChoiceField(
queryset=Site.objects.annotate( queryset=Site.objects.all(),
filter_count=Count('clusters')
),
to_field_name='slug', to_field_name='slug',
null_label='-- None --', null_label='-- None --',
required=False, required=False,
widget=APISelectMultiple(
api_url="/api/dcim/sites/",
value_field='slug',
null_option=True,
)
) )
class ClusterAddDevicesForm(BootstrapMixin, ChainedFieldsMixin, forms.Form): class ClusterAddDevicesForm(BootstrapMixin, ChainedFieldsMixin, forms.Form):
region = TreeNodeChoiceField( region = forms.ModelChoiceField(
queryset=Region.objects.all(), queryset=Region.objects.all(),
required=False, required=False,
widget=forms.Select( widget=APISelect(
api_url="/api/dcim/regions/",
filter_for={
"site": "region_id",
},
attrs={ attrs={
'filter-for': 'site',
'nullable': 'true', 'nullable': 'true',
} }
) )
@ -200,9 +229,10 @@ class ClusterAddDevicesForm(BootstrapMixin, ChainedFieldsMixin, forms.Form):
), ),
required=False, required=False,
widget=APISelect( widget=APISelect(
api_url='/api/dcim/sites/?region_id={{region}}', api_url='/api/dcim/sites/',
attrs={ filter_for={
'filter-for': 'rack', "rack": "site_id",
"devices": "site_id",
} }
) )
) )
@ -213,9 +243,11 @@ class ClusterAddDevicesForm(BootstrapMixin, ChainedFieldsMixin, forms.Form):
), ),
required=False, required=False,
widget=APISelect( widget=APISelect(
api_url='/api/dcim/racks/?site_id={{site}}', api_url='/api/dcim/racks/',
filter_for={
"devices": "rack_id"
},
attrs={ attrs={
'filter-for': 'devices',
'nullable': 'true', 'nullable': 'true',
} }
) )
@ -227,7 +259,7 @@ class ClusterAddDevicesForm(BootstrapMixin, ChainedFieldsMixin, forms.Form):
('rack', 'rack'), ('rack', 'rack'),
), ),
widget=APISelectMultiple( widget=APISelectMultiple(
api_url='/api/dcim/devices/?site_id={{site}}&rack_id={{rack}}', api_url='/api/dcim/devices/',
display_field='display_name', display_field='display_name',
disabled_indicator='cluster' disabled_indicator='cluster'
) )
@ -275,9 +307,12 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
cluster_group = forms.ModelChoiceField( cluster_group = forms.ModelChoiceField(
queryset=ClusterGroup.objects.all(), queryset=ClusterGroup.objects.all(),
required=False, required=False,
widget=forms.Select( widget=APISelect(
api_url='/api/virtualization/cluster-groups/',
filter_for={
"cluster": "group_id",
},
attrs={ attrs={
'filter-for': 'cluster',
'nullable': 'true', 'nullable': 'true',
} }
) )
@ -288,7 +323,7 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
('group', 'cluster_group'), ('group', 'cluster_group'),
), ),
widget=APISelect( widget=APISelect(
api_url='/api/virtualization/clusters/?group_id={{cluster_group}}' api_url='/api/virtualization/clusters/'
) )
) )
tags = TagField( tags = TagField(
@ -308,6 +343,20 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
'local_context_data': "Local config context data overwrites all sources contexts in the final rendered " 'local_context_data': "Local config context data overwrites all sources contexts in the final rendered "
"config context", "config context",
} }
widgets = {
"status": StaticSelect2(),
"role": APISelect(
api_url="/api/dcim/device-roles/",
additional_query_params={
"vm_role": "true"
}
),
'primary_ip4': StaticSelect2(),
'primary_ip6': StaticSelect2(),
'platform': APISelect(
api_url='/api/dcim/platforms/'
)
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -413,25 +462,41 @@ class VirtualMachineBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldB
status = forms.ChoiceField( status = forms.ChoiceField(
choices=add_blank_choice(VM_STATUS_CHOICES), choices=add_blank_choice(VM_STATUS_CHOICES),
required=False, required=False,
initial='' initial='',
widget=StaticSelect2(),
) )
cluster = forms.ModelChoiceField( cluster = forms.ModelChoiceField(
queryset=Cluster.objects.all(), queryset=Cluster.objects.all(),
required=False required=False,
widget=APISelect(
api_url='/api/virtualization/clusters/'
)
) )
role = forms.ModelChoiceField( role = forms.ModelChoiceField(
queryset=DeviceRole.objects.filter( queryset=DeviceRole.objects.filter(
vm_role=True vm_role=True
), ),
required=False required=False,
widget=APISelect(
api_url="/api/dcim/device-roles/",
additional_query_params={
"vm_role": "true"
}
)
) )
tenant = forms.ModelChoiceField( tenant = forms.ModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False required=False,
widget=APISelect(
api_url='/api/tenancy/tenants/'
)
) )
platform = forms.ModelChoiceField( platform = forms.ModelChoiceField(
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
required=False required=False,
widget=APISelect(
api_url='/api/dcim/platforms/'
)
) )
vcpus = forms.IntegerField( vcpus = forms.IntegerField(
required=False, required=False,
@ -464,59 +529,87 @@ class VirtualMachineFilterForm(BootstrapMixin, CustomFieldFilterForm):
cluster_group = FilterChoiceField( cluster_group = FilterChoiceField(
queryset=ClusterGroup.objects.all(), queryset=ClusterGroup.objects.all(),
to_field_name='slug', to_field_name='slug',
null_label='-- None --' null_label='-- None --',
widget=APISelectMultiple(
api_url='/api/virtualization/cluster-groups/',
value_field="slug",
null_option=True,
)
) )
cluster_type = FilterChoiceField( cluster_type = FilterChoiceField(
queryset=ClusterType.objects.all(), queryset=ClusterType.objects.all(),
to_field_name='slug', to_field_name='slug',
null_label='-- None --' null_label='-- None --',
widget=APISelectMultiple(
api_url='/api/virtualization/cluster-types/',
value_field="slug",
null_option=True,
)
) )
cluster_id = FilterChoiceField( cluster_id = FilterChoiceField(
queryset=Cluster.objects.annotate( queryset=Cluster.objects.all(),
filter_count=Count('virtual_machines') label='Cluster',
), widget=APISelectMultiple(
label='Cluster' api_url='/api/virtualization/clusters/',
)
) )
region = FilterTreeNodeMultipleChoiceField( region = FilterChoiceField(
queryset=Region.objects.all(), queryset=Region.objects.all(),
to_field_name='slug', to_field_name='slug',
required=False, required=False,
widget=APISelectMultiple(
api_url='/api/dcim/regions/',
value_field="slug",
null_option=True,
)
) )
site = FilterChoiceField( site = FilterChoiceField(
queryset=Site.objects.annotate( queryset=Site.objects.all(),
filter_count=Count('clusters__virtual_machines')
),
to_field_name='slug', to_field_name='slug',
null_label='-- None --' null_label='-- None --',
widget=APISelectMultiple(
api_url='/api/dcim/sites/',
value_field="slug",
null_option=True,
)
) )
role = FilterChoiceField( role = FilterChoiceField(
queryset=DeviceRole.objects.filter( queryset=DeviceRole.objects.filter(vm_role=True),
vm_role=True
).annotate(
filter_count=Count('virtual_machines')
),
to_field_name='slug', to_field_name='slug',
null_label='-- None --' null_label='-- None --',
widget=APISelectMultiple(
api_url='/api/dcim/device-roles/',
value_field="slug",
null_option=True,
additional_query_params={
'vm_role': 'true'
}
)
) )
status = AnnotatedMultipleChoiceField( status = forms.MultipleChoiceField(
choices=VM_STATUS_CHOICES, choices=VM_STATUS_CHOICES,
annotate=VirtualMachine.objects.all(), required=False,
annotate_field='status', widget=StaticSelect2Multiple()
required=False
) )
tenant = FilterChoiceField( tenant = FilterChoiceField(
queryset=Tenant.objects.annotate( queryset=Tenant.objects.all(),
filter_count=Count('virtual_machines')
),
to_field_name='slug', to_field_name='slug',
null_label='-- None --' null_label='-- None --',
widget=APISelectMultiple(
api_url='/api/tenancy/tenants/',
value_field="slug",
null_option=True,
)
) )
platform = FilterChoiceField( platform = FilterChoiceField(
queryset=Platform.objects.annotate( queryset=Platform.objects.all(),
filter_count=Count('virtual_machines')
),
to_field_name='slug', to_field_name='slug',
null_label='-- None --' null_label='-- None --',
widget=APISelectMultiple(
api_url='/api/dcim/platforms/',
value_field="slug",
null_option=True,
)
) )
@ -538,6 +631,7 @@ class InterfaceForm(BootstrapMixin, forms.ModelForm):
widgets = { widgets = {
'virtual_machine': forms.HiddenInput(), 'virtual_machine': forms.HiddenInput(),
'form_factor': forms.HiddenInput(), 'form_factor': forms.HiddenInput(),
'mode': StaticSelect2()
} }
labels = { labels = {
'mode': '802.1Q Mode', 'mode': '802.1Q Mode',