1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Reimplemented FilterChoiceField

This commit is contained in:
Jeremy Stretch
2016-09-20 11:08:25 -04:00
parent e3f0a12313
commit e618bf40ec
6 changed files with 84 additions and 95 deletions

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.db.models import Count
from dcim.models import Site, Device, Interface, Rack, IFACE_FF_VIRTUAL from dcim.models import Site, Device, Interface, Rack, IFACE_FF_VIRTUAL
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
@ -6,7 +7,7 @@ from tenancy.forms import bulkedit_tenant_choices
from tenancy.models import Tenant from tenancy.models import Tenant
from utilities.forms import ( from utilities.forms import (
APISelect, BootstrapMixin, BulkImportForm, CommentField, CSVDataField, FilterChoiceField, Livesearch, SmallTextarea, APISelect, BootstrapMixin, BulkImportForm, CommentField, CSVDataField, FilterChoiceField, Livesearch, SmallTextarea,
SlugField, get_filter_choices, SlugField,
) )
from .models import Circuit, CircuitType, Provider from .models import Circuit, CircuitType, Provider
@ -59,7 +60,7 @@ class ProviderBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm): class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Provider model = Provider
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug')) site = FilterChoiceField(queryset=Site.objects.all(), to_field_name='slug')
# #
@ -185,8 +186,10 @@ class CircuitBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm): class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Circuit model = Circuit
type = FilterChoiceField(choices=get_filter_choices(CircuitType, id_field='slug', count_field='circuits')) type = FilterChoiceField(queryset=CircuitType.objects.annotate(filter_count=Count('circuits')),
provider = FilterChoiceField(choices=get_filter_choices(Provider, id_field='slug', count_field='circuits')) to_field_name='slug')
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='circuits', provider = FilterChoiceField(queryset=Provider.objects.annotate(filter_count=Count('circuits')),
null_option='None')) to_field_name='slug')
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='circuits')) tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('circuits')), to_field_name='slug',
null_option=(0, 'None'))
site = FilterChoiceField(queryset=Site.objects.annotate(filter_count=Count('circuits')), to_field_name='slug')

View File

@ -1,7 +1,7 @@
import re import re
from django import forms from django import forms
from django.db.models import Q from django.db.models import Count, Q
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
from ipam.models import IPAddress from ipam.models import IPAddress
@ -10,7 +10,6 @@ from tenancy.models import Tenant
from utilities.forms import ( from utilities.forms import (
APISelect, add_blank_choice, BootstrapMixin, BulkImportForm, CommentField, CSVDataField, ExpandableNameField, APISelect, add_blank_choice, BootstrapMixin, BulkImportForm, CommentField, CSVDataField, ExpandableNameField,
FilterChoiceField, FlexibleModelChoiceField, Livesearch, SelectWithDisabled, SmallTextarea, SlugField, FilterChoiceField, FlexibleModelChoiceField, Livesearch, SelectWithDisabled, SmallTextarea, SlugField,
get_filter_choices
) )
from .models import ( from .models import (
@ -120,8 +119,8 @@ class SiteBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
class SiteFilterForm(BootstrapMixin, CustomFieldFilterForm): class SiteFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Site model = Site
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='sites', tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('sites')), to_field_name='slug',
null_option='None')) null_option=(0, 'None'))
# #
@ -137,7 +136,7 @@ class RackGroupForm(forms.ModelForm, BootstrapMixin):
class RackGroupFilterForm(forms.Form, BootstrapMixin): class RackGroupFilterForm(forms.Form, BootstrapMixin):
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='rack_groups')) site = FilterChoiceField(queryset=Site.objects.annotate(filter_count=Count('rack_groups')), to_field_name='slug')
# #
@ -246,14 +245,13 @@ class RackBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
class RackFilterForm(BootstrapMixin, CustomFieldFilterForm): class RackFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Rack model = Rack
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='racks')) site = FilterChoiceField(queryset=Site.objects.annotate(filter_count=Count('racks')), to_field_name='slug')
group_id = FilterChoiceField(choices=get_filter_choices(RackGroup, select_related=['site'], count_field='racks', group_id = FilterChoiceField(queryset=RackGroup.objects.select_related('site')
null_option='None'), .annotate(filter_count=Count('racks')), label='Rack group', null_option=(0, 'None'))
label='Rack Group') tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('racks')), to_field_name='slug',
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='racks', null_option=(0, 'None'))
null_option='None')) role = FilterChoiceField(queryset=RackRole.objects.annotate(filter_count=Count('racks')), to_field_name='slug',
role = FilterChoiceField(choices=get_filter_choices(RackRole, id_field='slug', count_field='racks', null_option=(0, 'None'))
null_option='None'))
# #
@ -288,8 +286,8 @@ class DeviceTypeBulkEditForm(forms.Form, BootstrapMixin):
class DeviceTypeFilterForm(forms.Form, BootstrapMixin): class DeviceTypeFilterForm(forms.Form, BootstrapMixin):
manufacturer = FilterChoiceField(choices=get_filter_choices(Manufacturer, id_field='slug', manufacturer = FilterChoiceField(queryset=Manufacturer.objects.annotate(filter_count=Count('device_types')),
count_field='device_types')) to_field_name='slug')
# #
@ -594,18 +592,16 @@ class DeviceBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm): class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Device model = Device
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='racks__devices')) site = FilterChoiceField(queryset=Site.objects.annotate(filter_count=Count('racks__devices')), to_field_name='slug')
rack_group_id = FilterChoiceField(choices=get_filter_choices(RackGroup, select_related=['site'], rack_group_id = FilterChoiceField(queryset=Site.objects.annotate(filter_count=Count('racks__devices')),
count_field='racks__devices'),
label='Rack Group') label='Rack Group')
role = FilterChoiceField(choices=get_filter_choices(DeviceRole, id_field='slug', count_field='devices')) role = FilterChoiceField(queryset=DeviceRole.objects.annotate(filter_count=Count('devices')), to_field_name='slug')
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='devices', tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('devices')), to_field_name='slug',
null_option='None')) null_option=(0, 'None'))
device_type_id = FilterChoiceField(choices=get_filter_choices(DeviceType, select_related=['manufacturer'], device_type_id = FilterChoiceField(queryset=DeviceType.objects.select_related('manufacturer')
count_field='instances'), .annotate(filter_count=Count('instances')), label='Type')
label='Type') platform = FilterChoiceField(queryset=Platform.objects.annotate(filter_count=Count('devices')),
platform = FilterChoiceField(choices=get_filter_choices(Platform, id_field='slug', count_field='devices', to_field_name='slug', null_option=(0, 'None'))
null_option='None'))
status = forms.NullBooleanField(required=False, widget=forms.Select(choices=FORM_STATUS_CHOICES)) status = forms.NullBooleanField(required=False, widget=forms.Select(choices=FORM_STATUS_CHOICES))

View File

@ -7,7 +7,6 @@ from tenancy.forms import bulkedit_tenant_choices
from tenancy.models import Tenant from tenancy.models import Tenant
from utilities.forms import ( from utilities.forms import (
APISelect, BootstrapMixin, CSVDataField, BulkImportForm, FilterChoiceField, Livesearch, SlugField, APISelect, BootstrapMixin, CSVDataField, BulkImportForm, FilterChoiceField, Livesearch, SlugField,
get_filter_choices,
) )
from .models import ( from .models import (
@ -74,8 +73,8 @@ class VRFBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
class VRFFilterForm(BootstrapMixin, CustomFieldFilterForm): class VRFFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = VRF model = VRF
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='vrfs', tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('vrfs')), to_field_name='slug',
null_option='None')) null_option=(0, None))
# #
@ -129,7 +128,8 @@ class AggregateBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
class AggregateFilterForm(BootstrapMixin, CustomFieldFilterForm): class AggregateFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Aggregate model = Aggregate
family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family') family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family')
rir = FilterChoiceField(choices=get_filter_choices(RIR, id_field='slug', count_field='aggregates'), label='RIR') rir = FilterChoiceField(queryset=RIR.objects.annotate(filter_count=Count('aggregates')), to_field_name='slug',
label='RIR')
# #
@ -273,16 +273,15 @@ class PrefixFilterForm(BootstrapMixin, CustomFieldFilterForm):
'placeholder': 'Network', 'placeholder': 'Network',
})) }))
family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family') family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family')
vrf = FilterChoiceField(choices=get_filter_choices(VRF, count_field='prefixes', null_option='Global'), vrf = FilterChoiceField(queryset=VRF.objects.annotate(filter_count=Count('prefixes')), to_field_name='slug',
label='VRF') label='VRF', null_option=(0, 'Global'))
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='prefixes', tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('prefixes')), to_field_name='slug',
null_option='None'), null_option=(0, 'None'))
label='Tenant') status = forms.MultipleChoiceField(choices=prefix_status_choices)
status = FilterChoiceField(choices=prefix_status_choices) site = FilterChoiceField(queryset=Site.objects.annotate(filter_count=Count('prefixes')), to_field_name='slug',
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='prefixes', null_option=(0, 'None'))
null_option='None')) role = FilterChoiceField(queryset=Role.objects.annotate(filter_count=Count('prefixes')), to_field_name='slug',
role = FilterChoiceField(choices=get_filter_choices(Role, id_field='slug', count_field='prefixes', null_option=(0, 'None'))
null_option='None'))
expand = forms.BooleanField(required=False, label='Expand prefix hierarchy') expand = forms.BooleanField(required=False, label='Expand prefix hierarchy')
@ -419,11 +418,10 @@ class IPAddressFilterForm(BootstrapMixin, CustomFieldFilterForm):
'placeholder': 'Prefix', 'placeholder': 'Prefix',
})) }))
family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family') family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family')
vrf = FilterChoiceField(choices=get_filter_choices(VRF, count_field='ip_addresses', null_option='None'), vrf = FilterChoiceField(queryset=VRF.objects.annotate(filter_count=Count('ip_addresses')), to_field_name='slug',
label='VRF') label='VRF', null_option=(0, 'Global'))
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='ip_addresses', tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('ip_addresses')),
null_option='None'), to_field_name='slug', null_option=(0, 'None'))
label='Tenant')
# #
@ -439,7 +437,7 @@ class VLANGroupForm(forms.ModelForm, BootstrapMixin):
class VLANGroupFilterForm(forms.Form, BootstrapMixin): class VLANGroupFilterForm(forms.Form, BootstrapMixin):
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='vlan_groups')) site = FilterChoiceField(queryset=Site.objects.annotate(filter_count=Count('vlan_groups')), to_field_name='slug')
# #
@ -526,11 +524,11 @@ def vlan_status_choices():
class VLANFilterForm(BootstrapMixin, CustomFieldFilterForm): class VLANFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = VLAN model = VLAN
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='vlans')) site = FilterChoiceField(queryset=Site.objects.annotate(filter_count=Count('vlans')), to_field_name='slug')
group_id = FilterChoiceField(choices=get_filter_choices(VLANGroup, select_related=['site'], count_field='vlans', group_id = FilterChoiceField(queryset=VLANGroup.objects.annotate(filter_count=Count('vlans')), label='VLAN group',
null_option='None'), null_option=(0, 'None'))
label='VLAN Group') tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('vlans')), to_field_name='slug',
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='vlans', null_option=(0, 'None'))
null_option='None')) status = forms.MultipleChoiceField(choices=vlan_status_choices)
status = FilterChoiceField(choices=vlan_status_choices) role = FilterChoiceField(queryset=Role.objects.annotate(filter_count=Count('vlans')), to_field_name='slug',
role = FilterChoiceField(choices=get_filter_choices(Role, id_field='slug', count_field='vlans', null_option='None')) null_option=(0, 'None'))

View File

@ -2,11 +2,10 @@ 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 dcim.models import Device from dcim.models import Device
from utilities.forms import ( from utilities.forms import BootstrapMixin, BulkImportForm, CSVDataField, FilterChoiceField, SlugField
BootstrapMixin, BulkImportForm, CSVDataField, FilterChoiceField, SlugField, get_filter_choices,
)
from .models import Secret, SecretRole, UserKey from .models import Secret, SecretRole, UserKey
@ -97,7 +96,7 @@ class SecretBulkEditForm(forms.Form, BootstrapMixin):
class SecretFilterForm(forms.Form, BootstrapMixin): class SecretFilterForm(forms.Form, BootstrapMixin):
role = FilterChoiceField(choices=get_filter_choices(SecretRole, id_field='slug', count_field='secrets')) role = FilterChoiceField(queryset=SecretRole.objects.annotate(filter_count=Count('secrets')), to_field_name='slug')
# #

View File

@ -1,9 +1,8 @@
from django import forms from django import forms
from django.db.models import Count
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
from utilities.forms import ( from utilities.forms import BootstrapMixin, BulkImportForm, CommentField, CSVDataField, FilterChoiceField, SlugField
BootstrapMixin, BulkImportForm, CommentField, CSVDataField, FilterChoiceField, SlugField, get_filter_choices,
)
from .models import Tenant, TenantGroup from .models import Tenant, TenantGroup
@ -77,5 +76,5 @@ class TenantBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
class TenantFilterForm(BootstrapMixin, CustomFieldFilterForm): class TenantFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Tenant model = Tenant
group = FilterChoiceField(choices=get_filter_choices(TenantGroup, id_field='slug', count_field='tenants', group = FilterChoiceField(queryset=TenantGroup.objects.annotate(filter_count=Count('tenants')),
null_option='None')) to_field_name='slug', null_option=(0, 'None'))

View File

@ -1,4 +1,5 @@
import csv import csv
import itertools
import re import re
from django import forms from django import forms
@ -35,29 +36,6 @@ def add_blank_choice(choices):
return ((None, '---------'),) + choices return ((None, '---------'),) + choices
def get_filter_choices(model, id_field='pk', select_related=[], count_field=None, null_option=None):
"""
Return a list of choices suitable for a ChoiceField.
:param model: The base model to use for the queryset
:param id_field: Field to use as the object identifier
:param select_related: Any related tables to include
:param count_field: The field to use for a child COUNT() (optional)
:param null_option: A choice to include at the beginning of the list serving as "null"
"""
queryset = model.objects.all()
if select_related:
queryset = queryset.select_related(*select_related)
if count_field:
queryset = queryset.annotate(child_count=Count(count_field))
choices = [(getattr(obj, id_field), u'{} ({})'.format(obj, obj.child_count)) for obj in queryset]
else:
choices = [(getattr(obj, id_field), u'{}'.format(obj)) for obj in queryset]
if null_option:
choices = [(0, null_option)] + choices
return choices
# #
# Widgets # Widgets
# #
@ -250,15 +228,31 @@ class SlugField(forms.SlugField):
self.widget.attrs['slug-source'] = slug_source self.widget.attrs['slug-source'] = slug_source
class FilterChoiceField(forms.MultipleChoiceField): class FilterChoiceField(forms.ModelMultipleChoiceField):
iterator = forms.models.ModelChoiceIterator
def __init__(self, *args, **kwargs): def __init__(self, null_option=None, *args, **kwargs):
self.null_option = null_option
if 'required' not in kwargs: if 'required' not in kwargs:
kwargs['required'] = False kwargs['required'] = False
if 'widget' not in kwargs: if 'widget' not in kwargs:
kwargs['widget'] = forms.SelectMultiple(attrs={'size': 6}) kwargs['widget'] = forms.SelectMultiple(attrs={'size': 6})
super(FilterChoiceField, self).__init__(*args, **kwargs) super(FilterChoiceField, self).__init__(*args, **kwargs)
def label_from_instance(self, obj):
if hasattr(obj, 'filter_count'):
return u'{} ({})'.format(obj, obj.filter_count)
return force_text(obj)
def _get_choices(self):
if hasattr(self, '_choices'):
return self._choices
if self.null_option is not None:
return itertools.chain([self.null_option], self.iterator(self))
return self.iterator(self)
choices = property(_get_choices, forms.ChoiceField._set_choices)
# #
# Forms # Forms