class ObjectChangeFilterForm(BootstrapMixin, forms.Form): model = ObjectChange q = forms.CharField(required=False, label='Search') time_after = forms.DateTimeField(label='After', required=False, widget=DateTimePicker()) time_before = forms.DateTimeField(label='Before', required=False, widget=DateTimePicker()) action = forms.ChoiceField( choices=add_blank_choice(ObjectChangeActionChoices), required=False, widget=StaticSelect2()) # TODO: Convert to DynamicModelMultipleChoiceField once we have an API endpoint for users user = forms.ModelChoiceField(queryset=User.objects.order_by('username'), required=False, widget=StaticSelect2()) changed_object_type = forms.ModelChoiceField( queryset=ContentType.objects.order_by('model'), required=False, widget=ContentTypeSelect(), label='Object Type')
class ObjectChangeFilterForm(BootstrapMixin, forms.Form): model = ObjectChange q = forms.CharField(required=False, label='Search') time_after = forms.DateTimeField(label='After', required=False, widget=DateTimePicker()) time_before = forms.DateTimeField(label='Before', required=False, widget=DateTimePicker()) action = forms.ChoiceField( choices=add_blank_choice(ObjectChangeActionChoices), required=False, widget=StaticSelect2()) user = DynamicModelMultipleChoiceField(queryset=User.objects.all(), required=False, display_field='username', widget=APISelectMultiple( api_url='/api/users/users/', )) changed_object_type = forms.ModelChoiceField( queryset=ContentType.objects.order_by('model'), required=False, widget=ContentTypeSelect(), label='Object Type')
class VLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm): pk = forms.ModelMultipleChoiceField(queryset=VLAN.objects.all(), widget=forms.MultipleHiddenInput()) site = DynamicModelChoiceField(queryset=Site.objects.all(), required=False) group = DynamicModelChoiceField(queryset=VLANGroup.objects.all(), required=False) tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False) status = forms.ChoiceField(choices=add_blank_choice(VLANStatusChoices), required=False, widget=StaticSelect2()) role = DynamicModelChoiceField(queryset=Role.objects.all(), required=False) description = forms.CharField(max_length=100, required=False) class Meta: nullable_fields = [ 'site', 'group', 'tenant', 'role', 'description', ]
class ObjectChangeFilterForm(BootstrapMixin, forms.Form): model = ObjectChange q = forms.CharField(required=False, label=_('Search')) time_after = forms.DateTimeField(required=False, label=_('After'), widget=DateTimePicker()) time_before = forms.DateTimeField(required=False, label=_('Before'), widget=DateTimePicker()) action = forms.ChoiceField( choices=add_blank_choice(ObjectChangeActionChoices), required=False, widget=StaticSelect2()) user_id = DynamicModelMultipleChoiceField( queryset=User.objects.all(), required=False, label=_('User'), widget=APISelectMultiple(api_url='/api/users/users/', )) changed_object_type_id = DynamicModelMultipleChoiceField( queryset=ContentType.objects.all(), required=False, label=_('Object Type'), widget=APISelectMultiple(api_url='/api/extras/content-types/', ))
class VirtualMachineBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm): pk = forms.ModelMultipleChoiceField(queryset=VirtualMachine.objects.all(), widget=forms.MultipleHiddenInput) status = forms.ChoiceField(choices=add_blank_choice(VM_STATUS_CHOICES), required=False, initial='') cluster = forms.ModelChoiceField(queryset=Cluster.objects.all(), required=False) role = forms.ModelChoiceField( queryset=DeviceRole.objects.filter(vm_role=True), required=False) tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False) platform = forms.ModelChoiceField(queryset=Platform.objects.all(), required=False) vcpus = forms.IntegerField(required=False, label='vCPUs') memory = forms.IntegerField(required=False, label='Memory (MB)') disk = forms.IntegerField(required=False, label='Disk (GB)') comments = CommentField(widget=SmallTextarea) class Meta: nullable_fields = [ 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments' ]
class AggregateFilterForm(BootstrapMixin, CustomFieldFilterForm): model = Aggregate q = forms.CharField( required=False, label='Search' ) family = forms.ChoiceField( required=False, choices=add_blank_choice(IPAddressFamilyChoices), label='Address family', widget=StaticSelect2() ) rir = DynamicModelMultipleChoiceField( queryset=RIR.objects.all(), to_field_name='slug', required=False, label='RIR', widget=APISelectMultiple( api_url="/api/ipam/rirs/", value_field="slug", ) ) tag = TagFilterField(model)
class JournalEntryFilterForm(BootstrapMixin, forms.Form): model = JournalEntry q = forms.CharField( required=False, label=_('Search') ) created_after = forms.DateTimeField( required=False, label=_('After'), widget=DateTimePicker() ) created_before = forms.DateTimeField( required=False, label=_('Before'), widget=DateTimePicker() ) created_by_id = DynamicModelMultipleChoiceField( queryset=User.objects.all(), required=False, label=_('User'), widget=APISelectMultiple( api_url='/api/users/users/', ) ) assigned_object_type_id = DynamicModelMultipleChoiceField( queryset=ContentType.objects.all(), required=False, label=_('Object Type'), widget=APISelectMultiple( api_url='/api/extras/content-types/', ) ) kind = forms.ChoiceField( choices=add_blank_choice(JournalEntryKindChoices), required=False, widget=StaticSelect2() )
class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm): pk = forms.ModelMultipleChoiceField(queryset=Prefix.objects.all(), widget=forms.MultipleHiddenInput()) site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False, widget=APISelect(api_url="/api/dcim/sites/")) vrf = forms.ModelChoiceField(queryset=VRF.objects.all(), required=False, label='VRF', widget=APISelect(api_url="/api/ipam/vrfs/")) prefix_length = forms.IntegerField(min_value=PREFIX_LENGTH_MIN, max_value=PREFIX_LENGTH_MAX, required=False) tenant = forms.ModelChoiceField( queryset=Tenant.objects.all(), required=False, widget=APISelect(api_url="/api/tenancy/tenants/")) status = forms.ChoiceField(choices=add_blank_choice(PrefixStatusChoices), required=False, widget=StaticSelect2()) role = forms.ModelChoiceField(queryset=Role.objects.all(), required=False, widget=APISelect(api_url="/api/ipam/roles/")) is_pool = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect(), label='Is a pool') description = forms.CharField(max_length=100, required=False) class Meta: nullable_fields = [ 'site', 'vrf', 'tenant', 'role', 'description', ]
class IPRangeFilterForm(TenancyFilterForm, CustomFieldModelFilterForm): model = IPRange field_groups = [ ['q', 'tag'], ['family', 'vrf_id', 'status', 'role_id'], ['tenant_group_id', 'tenant_id'], ] family = forms.ChoiceField( required=False, choices=add_blank_choice(IPAddressFamilyChoices), label=_('Address family'), widget=StaticSelect()) vrf_id = DynamicModelMultipleChoiceField(queryset=VRF.objects.all(), required=False, label=_('Assigned VRF'), null_option='Global') status = forms.MultipleChoiceField(choices=PrefixStatusChoices, required=False, widget=StaticSelectMultiple()) role_id = DynamicModelMultipleChoiceField(queryset=Role.objects.all(), required=False, null_option='None', label=_('Role')) tag = TagFilterField(model)
class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm): pk = forms.ModelMultipleChoiceField(queryset=Prefix.objects.all(), widget=forms.MultipleHiddenInput()) region = DynamicModelChoiceField(queryset=Region.objects.all(), required=False, to_field_name='slug') site = DynamicModelChoiceField(queryset=Site.objects.all(), required=False, query_params={'region': '$region'}) vrf = DynamicModelChoiceField(queryset=VRF.objects.all(), required=False, label='VRF', display_field='display_name') prefix_length = forms.IntegerField(min_value=PREFIX_LENGTH_MIN, max_value=PREFIX_LENGTH_MAX, required=False) tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False) status = forms.ChoiceField(choices=add_blank_choice(PrefixStatusChoices), required=False, widget=StaticSelect2()) role = DynamicModelChoiceField(queryset=Role.objects.all(), required=False) is_pool = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect(), label='Is a pool') description = forms.CharField(max_length=100, required=False) class Meta: nullable_fields = [ 'site', 'vrf', 'tenant', 'role', 'description', ]
class DiscoveryRequestFilterForm(BootstrapMixin, forms.Form): model = DiscoveryRequest field_order = ['q', 'status', 'prefix', 'update_existing', 'platform', 'site'] q = forms.CharField( required=False, label='Search' ) status = forms.ChoiceField( choices=add_blank_choice(REQUEST_STATUS_CHOICES), required=False, widget=StaticSelect2() ) platform = FilterChoiceField( queryset=Platform.objects.all(), to_field_name='slug', widget=APISelectMultiple( api_url="/api/dcim/platforms/", value_field="slug", ) ) site = FilterChoiceField( queryset=Site.objects.all(), to_field_name='slug', widget=APISelectMultiple( api_url="/api/dcim/sites/", value_field="slug", ) ) device_role = FilterChoiceField( queryset=DeviceRole.objects.all(), to_field_name='slug', widget=APISelectMultiple( api_url="/api/dcim/device-roles/", value_field="slug", ) )
class SiteForm(TenancyForm, CustomFieldModelForm): region = DynamicModelChoiceField(queryset=Region.objects.all(), required=False) group = DynamicModelChoiceField(queryset=SiteGroup.objects.all(), required=False) asns = DynamicModelMultipleChoiceField(queryset=ASN.objects.all(), label=_('ASNs'), required=False) slug = SlugField() time_zone = TimeZoneFormField(choices=add_blank_choice( TimeZoneFormField().choices), required=False, widget=StaticSelect()) comments = CommentField() tags = DynamicModelMultipleChoiceField(queryset=Tag.objects.all(), required=False) class Meta: model = Site fields = [ 'name', 'slug', 'status', 'region', 'group', 'tenant_group', 'tenant', 'facility', 'asn', 'asns', 'time_zone', 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'contact_name', 'contact_phone', 'contact_email', 'comments', 'tags', ] fieldsets = ( ('Site', ( 'name', 'slug', 'status', 'region', 'group', 'facility', 'asn', 'asns', 'time_zone', 'description', 'tags', )), ('Tenancy', ('tenant_group', 'tenant')), ('Contact Info', ( 'physical_address', 'shipping_address', 'latitude', 'longitude', 'contact_name', 'contact_phone', 'contact_email', )), ) widgets = { 'physical_address': SmallTextarea(attrs={ 'rows': 3, }), 'shipping_address': SmallTextarea(attrs={ 'rows': 3, }), 'status': StaticSelect(), 'time_zone': StaticSelect(), } help_texts = { 'name': "Full name of the site", 'asn': "BGP autonomous system number. This field is depreciated in favour of the ASN model", 'facility': "Data center provider and facility (e.g. Equinix NY7)", 'time_zone': "Local time zone", 'description': "Short description (will appear in sites list)", 'physical_address': "Physical location of the building (e.g. for GPS)", 'shipping_address': "If different from the physical address", 'latitude': "Latitude in decimal format (xx.yyyyyy)", 'longitude': "Longitude in decimal format (xx.yyyyyy)" }
class ServiceFilterForm(BootstrapMixin, CustomFieldFilterForm): model = Service q = forms.CharField(required=False, label='Search') protocol = forms.ChoiceField(choices=add_blank_choice(IP_PROTOCOL_CHOICES), required=False) port = forms.IntegerField(required=False)
class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm): pk = forms.ModelMultipleChoiceField( queryset=Interface.objects.all(), widget=forms.MultipleHiddenInput() ) enabled = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect() ) mtu = forms.IntegerField( required=False, min_value=INTERFACE_MTU_MIN, max_value=INTERFACE_MTU_MAX, label='MTU' ) description = forms.CharField( max_length=100, required=False ) mode = forms.ChoiceField( choices=add_blank_choice(InterfaceModeChoices), required=False, widget=StaticSelect2() ) untagged_vlan = forms.ModelChoiceField( queryset=VLAN.objects.all(), required=False, widget=APISelect( api_url="/api/ipam/vlans/", display_field='display_name', full=True ) ) tagged_vlans = forms.ModelMultipleChoiceField( queryset=VLAN.objects.all(), required=False, widget=APISelectMultiple( api_url="/api/ipam/vlans/", display_field='display_name', full=True ) ) class Meta: nullable_fields = [ 'mtu', 'description', ] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Limit VLan choices to those in: global vlans, global groups, the current site's group, the current site vlan_choices = [] global_vlans = VLAN.objects.filter(site=None, group=None) vlan_choices.append( ('Global', [(vlan.pk, vlan) for vlan in global_vlans]) ) for group in VLANGroup.objects.filter(site=None): global_group_vlans = VLAN.objects.filter(group=group) vlan_choices.append( (group.name, [(vlan.pk, vlan) for vlan in global_group_vlans]) ) if self.parent_obj.cluster is not None: site = getattr(self.parent_obj.cluster, 'site', None) if site is not None: # Add non-grouped site VLANs site_vlans = VLAN.objects.filter(site=site, group=None) vlan_choices.append((site.name, [(vlan.pk, vlan) for vlan in site_vlans])) # Add grouped site VLANs for group in VLANGroup.objects.filter(site=site): site_group_vlans = VLAN.objects.filter(group=group) vlan_choices.append(( '{} / {}'.format(group.site.name, group.name), [(vlan.pk, vlan) for vlan in site_group_vlans] )) self.fields['untagged_vlan'].choices = [(None, '---------')] + vlan_choices self.fields['tagged_vlans'].choices = vlan_choices
class InterfaceCreateForm(ComponentForm): name_pattern = ExpandableNameField( label='Name' ) type = forms.ChoiceField( choices=VMInterfaceTypeChoices, initial=VMInterfaceTypeChoices.TYPE_VIRTUAL, widget=forms.HiddenInput() ) enabled = forms.BooleanField( required=False ) mtu = forms.IntegerField( required=False, min_value=INTERFACE_MTU_MIN, max_value=INTERFACE_MTU_MAX, label='MTU' ) mac_address = forms.CharField( required=False, label='MAC Address' ) description = forms.CharField( max_length=100, required=False ) mode = forms.ChoiceField( choices=add_blank_choice(InterfaceModeChoices), required=False, widget=StaticSelect2(), ) untagged_vlan = forms.ModelChoiceField( queryset=VLAN.objects.all(), required=False, widget=APISelect( api_url="/api/ipam/vlans/", display_field='display_name', full=True ) ) tagged_vlans = forms.ModelMultipleChoiceField( queryset=VLAN.objects.all(), required=False, widget=APISelectMultiple( api_url="/api/ipam/vlans/", display_field='display_name', full=True ) ) tags = TagField( required=False ) def __init__(self, *args, **kwargs): # Set interfaces enabled by default kwargs['initial'] = kwargs.get('initial', {}).copy() kwargs['initial'].update({'enabled': True}) super().__init__(*args, **kwargs) # Limit VLan choices to those in: global vlans, global groups, the current site's group, the current site vlan_choices = [] global_vlans = VLAN.objects.filter(site=None, group=None) vlan_choices.append( ('Global', [(vlan.pk, vlan) for vlan in global_vlans]) ) for group in VLANGroup.objects.filter(site=None): global_group_vlans = VLAN.objects.filter(group=group) vlan_choices.append( (group.name, [(vlan.pk, vlan) for vlan in global_group_vlans]) ) site = getattr(self.parent.cluster, 'site', None) if site is not None: # Add non-grouped site VLANs site_vlans = VLAN.objects.filter(site=site, group=None) vlan_choices.append((site.name, [(vlan.pk, vlan) for vlan in site_vlans])) # Add grouped site VLANs for group in VLANGroup.objects.filter(site=site): site_group_vlans = VLAN.objects.filter(group=group) vlan_choices.append(( '{} / {}'.format(group.site.name, group.name), [(vlan.pk, vlan) for vlan in site_group_vlans] )) self.fields['untagged_vlan'].choices = [(None, '---------')] + vlan_choices self.fields['tagged_vlans'].choices = vlan_choices
def to_form_field(self, set_initial=True, enforce_required=True, for_csv_import=False): """ Return a form field suitable for setting a CustomField's value for an object. set_initial: Set initial date for the field. This should be False when generating a field for bulk editing. enforce_required: Honor the value of CustomField.required. Set to False for filtering/bulk editing. for_csv_import: Return a form field suitable for bulk import of objects in CSV format. """ initial = self.default if set_initial else None required = self.required if enforce_required else False # Integer if self.type == CustomFieldTypeChoices.TYPE_INTEGER: field = forms.IntegerField(required=required, initial=initial) # Boolean elif self.type == CustomFieldTypeChoices.TYPE_BOOLEAN: choices = ( (None, '---------'), (1, 'True'), (0, 'False'), ) if initial is not None and initial.lower() in ['true', 'yes', '1']: initial = 1 elif initial is not None and initial.lower() in ['false', 'no', '0']: initial = 0 else: initial = None field = forms.NullBooleanField( required=required, initial=initial, widget=StaticSelect2(choices=choices) ) # Date elif self.type == CustomFieldTypeChoices.TYPE_DATE: field = forms.DateField(required=required, initial=initial, widget=DatePicker()) # Select elif self.type == CustomFieldTypeChoices.TYPE_SELECT: choices = [(cfc.pk, cfc.value) for cfc in self.choices.all()] if not required: choices = add_blank_choice(choices) # Set the initial value to the PK of the default choice, if any if set_initial: default_choice = self.choices.filter(value=self.default).first() if default_choice: initial = default_choice.pk field_class = CSVChoiceField if for_csv_import else forms.ChoiceField field = field_class( choices=choices, required=required, initial=initial, widget=StaticSelect2() ) # URL elif self.type == CustomFieldTypeChoices.TYPE_URL: field = LaxURLField(required=required, initial=initial) # Text else: field = forms.CharField(max_length=255, required=required, initial=initial) field.model = self field.label = self.label if self.label else self.name.replace('_', ' ').capitalize() if self.description: field.help_text = self.description return field
class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = IPAddress field_order = [ 'q', 'parent', 'family', 'mask_length', 'vrf_id', 'present_in_vrf_id', 'status', 'role', 'assigned_to_interface', 'tenant_group_id', 'tenant_id', ] field_groups = [ ['q', 'tag'], [ 'parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface' ], ['vrf_id', 'present_in_vrf_id'], ['tenant_group_id', 'tenant_id'], ] q = forms.CharField( required=False, widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), label=_('Search')) parent = forms.CharField(required=False, widget=forms.TextInput(attrs={ 'placeholder': 'Prefix', }), label='Parent Prefix') family = forms.ChoiceField( required=False, choices=add_blank_choice(IPAddressFamilyChoices), label=_('Address family'), widget=StaticSelect()) mask_length = forms.ChoiceField(required=False, choices=IPADDRESS_MASK_LENGTH_CHOICES, label=_('Mask length'), widget=StaticSelect()) vrf_id = DynamicModelMultipleChoiceField(queryset=VRF.objects.all(), required=False, label=_('Assigned VRF'), null_option='Global', fetch_trigger='open') present_in_vrf_id = DynamicModelChoiceField(queryset=VRF.objects.all(), required=False, label=_('Present in VRF'), fetch_trigger='open') status = forms.MultipleChoiceField(choices=IPAddressStatusChoices, required=False, widget=StaticSelectMultiple()) role = forms.MultipleChoiceField(choices=IPAddressRoleChoices, required=False, widget=StaticSelectMultiple()) assigned_to_interface = forms.NullBooleanField( required=False, label=_('Assigned to an interface'), widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES)) tag = TagFilterField(model)
class PowerFeedFilterForm(BootstrapMixin, CustomFieldModelFilterForm): model = PowerFeed field_groups = [ ['q', 'tag'], ['region_id', 'site_group_id', 'site_id'], ['power_panel_id', 'rack_id'], [ 'status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization' ], ] q = forms.CharField( required=False, widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), label=_('Search')) region_id = DynamicModelMultipleChoiceField(queryset=Region.objects.all(), required=False, label=_('Region'), fetch_trigger='open') site_group_id = DynamicModelMultipleChoiceField( queryset=SiteGroup.objects.all(), required=False, label=_('Site group'), fetch_trigger='open') site_id = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), required=False, query_params={'region_id': '$region_id'}, label=_('Site'), fetch_trigger='open') power_panel_id = DynamicModelMultipleChoiceField( queryset=PowerPanel.objects.all(), required=False, null_option='None', query_params={'site_id': '$site_id'}, label=_('Power panel'), fetch_trigger='open') rack_id = DynamicModelMultipleChoiceField( queryset=Rack.objects.all(), required=False, null_option='None', query_params={'site_id': '$site_id'}, label=_('Rack'), fetch_trigger='open') status = forms.MultipleChoiceField(choices=PowerFeedStatusChoices, required=False, widget=StaticSelectMultiple()) type = forms.ChoiceField(choices=add_blank_choice(PowerFeedTypeChoices), required=False, widget=StaticSelect()) supply = forms.ChoiceField( choices=add_blank_choice(PowerFeedSupplyChoices), required=False, widget=StaticSelect()) phase = forms.ChoiceField(choices=add_blank_choice(PowerFeedPhaseChoices), required=False, widget=StaticSelect()) voltage = forms.IntegerField(required=False) amperage = forms.IntegerField(required=False) max_utilization = forms.IntegerField(required=False) tag = TagFilterField(model)
DynamicModelMultipleChoiceField, ExpandableIPAddressField, ReturnURLForm, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES, ) from virtualization.models import VirtualMachine from .choices import * from .constants import * from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF PREFIX_MASK_LENGTH_CHOICES = add_blank_choice([ (i, i) for i in range(PREFIX_LENGTH_MIN, PREFIX_LENGTH_MAX + 1) ]) IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([ (i, i) for i in range(IPADDRESS_MASK_LENGTH_MIN, IPADDRESS_MASK_LENGTH_MAX + 1) ]) # # VRFs # class VRFForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): tags = TagField(required=False)
class ConsoleServerPortTemplateCreateForm(ComponentTemplateCreateForm): type = forms.ChoiceField(choices=add_blank_choice(ConsolePortTypeChoices), widget=StaticSelect()) field_order = ('manufacturer', 'device_type', 'name_pattern', 'label_pattern', 'type', 'description')
class VMInterfaceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): pk = forms.ModelMultipleChoiceField( queryset=VMInterface.objects.all(), widget=forms.MultipleHiddenInput() ) virtual_machine = forms.ModelChoiceField( queryset=VirtualMachine.objects.all(), required=False, disabled=True, widget=forms.HiddenInput() ) enabled = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect() ) mtu = forms.IntegerField( required=False, min_value=INTERFACE_MTU_MIN, max_value=INTERFACE_MTU_MAX, label='MTU' ) description = forms.CharField( max_length=100, required=False ) mode = forms.ChoiceField( choices=add_blank_choice(InterfaceModeChoices), required=False, widget=StaticSelect2() ) untagged_vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, display_field='display_name', brief_mode=False, query_params={ 'site_id': 'null', } ) tagged_vlans = DynamicModelMultipleChoiceField( queryset=VLAN.objects.all(), required=False, display_field='display_name', brief_mode=False, query_params={ 'site_id': 'null', } ) class Meta: nullable_fields = [ 'mtu', 'description', ] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Limit available VLANs based on the parent VirtualMachine if 'virtual_machine' in self.initial: parent_obj = VirtualMachine.objects.filter(pk=self.initial['virtual_machine']).first() site = getattr(parent_obj.cluster, 'site', None) if site is not None: # Add current site to VLANs query params self.fields['untagged_vlan'].widget.add_query_param('site_id', site.pk) self.fields['tagged_vlans'].widget.add_query_param('site_id', site.pk)
class VMInterfaceCreateForm(BootstrapMixin, InterfaceCommonForm): virtual_machine = DynamicModelChoiceField( queryset=VirtualMachine.objects.all() ) name_pattern = ExpandableNameField( label='Name' ) enabled = forms.BooleanField( required=False, initial=True ) mtu = forms.IntegerField( required=False, min_value=INTERFACE_MTU_MIN, max_value=INTERFACE_MTU_MAX, label='MTU' ) mac_address = forms.CharField( required=False, label='MAC Address' ) description = forms.CharField( max_length=100, required=False ) mode = forms.ChoiceField( choices=add_blank_choice(InterfaceModeChoices), required=False, widget=StaticSelect2(), ) untagged_vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, display_field='display_name', brief_mode=False, query_params={ 'site_id': 'null', } ) tagged_vlans = DynamicModelMultipleChoiceField( queryset=VLAN.objects.all(), required=False, display_field='display_name', brief_mode=False, query_params={ 'site_id': 'null', } ) tags = DynamicModelMultipleChoiceField( queryset=Tag.objects.all(), required=False ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) virtual_machine = VirtualMachine.objects.get( pk=self.initial.get('virtual_machine') or self.data.get('virtual_machine') ) # Add current site to VLANs query params site = virtual_machine.site if site: self.fields['untagged_vlan'].widget.add_query_param('site_id', site.pk) self.fields['tagged_vlans'].widget.add_query_param('site_id', site.pk)
def to_form_field(self, set_initial=True, enforce_required=True, for_csv_import=False): """ Return a form field suitable for setting a CustomField's value for an object. set_initial: Set initial date for the field. This should be False when generating a field for bulk editing. enforce_required: Honor the value of CustomField.required. Set to False for filtering/bulk editing. for_csv_import: Return a form field suitable for bulk import of objects in CSV format. """ initial = self.default if set_initial else None required = self.required if enforce_required else False # Integer if self.type == CustomFieldTypeChoices.TYPE_INTEGER: field = forms.IntegerField( required=required, initial=initial, min_value=self.validation_minimum, max_value=self.validation_maximum ) # Boolean elif self.type == CustomFieldTypeChoices.TYPE_BOOLEAN: choices = ( (None, '---------'), (True, 'True'), (False, 'False'), ) field = forms.NullBooleanField( required=required, initial=initial, widget=StaticSelect(choices=choices) ) # Date elif self.type == CustomFieldTypeChoices.TYPE_DATE: field = forms.DateField(required=required, initial=initial, widget=DatePicker()) # Select elif self.type in (CustomFieldTypeChoices.TYPE_SELECT, CustomFieldTypeChoices.TYPE_MULTISELECT): choices = [(c, c) for c in self.choices] default_choice = self.default if self.default in self.choices else None if not required or default_choice is None: choices = add_blank_choice(choices) # Set the initial value to the first available choice (if any) if set_initial and default_choice: initial = default_choice if self.type == CustomFieldTypeChoices.TYPE_SELECT: field_class = CSVChoiceField if for_csv_import else forms.ChoiceField field = field_class( choices=choices, required=required, initial=initial, widget=StaticSelect() ) else: field_class = CSVChoiceField if for_csv_import else forms.MultipleChoiceField field = field_class( choices=choices, required=required, initial=initial, widget=StaticSelectMultiple() ) # URL elif self.type == CustomFieldTypeChoices.TYPE_URL: field = LaxURLField(required=required, initial=initial) # Text else: field = forms.CharField(max_length=255, required=required, initial=initial) if self.validation_regex: field.validators = [ RegexValidator( regex=self.validation_regex, message=mark_safe(f"Values must match this regex: <code>{self.validation_regex}</code>") ) ] field.model = self field.label = str(self) if self.description: field.help_text = escape(self.description) return field
class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = Prefix field_groups = [['q', 'tag'], [ 'within_include', 'family', 'status', 'role_id', 'mask_length', 'is_pool', 'mark_utilized' ], ['vrf_id', 'present_in_vrf_id'], ['region_id', 'site_group_id', 'site_id'], ['tenant_group_id', 'tenant_id']] q = forms.CharField( required=False, widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), label=_('Search')) mask_length__lte = forms.IntegerField(widget=forms.HiddenInput()) within_include = forms.CharField( required=False, widget=forms.TextInput(attrs={ 'placeholder': 'Prefix', }), label=_('Search within')) family = forms.ChoiceField( required=False, choices=add_blank_choice(IPAddressFamilyChoices), label=_('Address family'), widget=StaticSelect()) mask_length = forms.MultipleChoiceField(required=False, choices=PREFIX_MASK_LENGTH_CHOICES, label=_('Mask length'), widget=StaticSelectMultiple()) vrf_id = DynamicModelMultipleChoiceField(queryset=VRF.objects.all(), required=False, label=_('Assigned VRF'), null_option='Global', fetch_trigger='open') present_in_vrf_id = DynamicModelChoiceField(queryset=VRF.objects.all(), required=False, label=_('Present in VRF'), fetch_trigger='open') status = forms.MultipleChoiceField(choices=PrefixStatusChoices, required=False, widget=StaticSelectMultiple()) region_id = DynamicModelMultipleChoiceField(queryset=Region.objects.all(), required=False, label=_('Region'), fetch_trigger='open') site_group_id = DynamicModelMultipleChoiceField( queryset=SiteGroup.objects.all(), required=False, label=_('Site group'), fetch_trigger='open') site_id = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), required=False, null_option='None', query_params={'region_id': '$region_id'}, label=_('Site'), fetch_trigger='open') role_id = DynamicModelMultipleChoiceField(queryset=Role.objects.all(), required=False, null_option='None', label=_('Role'), fetch_trigger='open') is_pool = forms.NullBooleanField( required=False, label=_('Is a pool'), widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES)) mark_utilized = forms.NullBooleanField( required=False, label=_('Marked as 100% utilized'), widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES)) tag = TagFilterField(model)
class VirtualMachineBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm): pk = forms.ModelMultipleChoiceField( queryset=VirtualMachine.objects.all(), widget=forms.MultipleHiddenInput() ) status = forms.ChoiceField( choices=add_blank_choice(VirtualMachineStatusChoices), required=False, initial='', widget=StaticSelect2(), ) cluster = forms.ModelChoiceField( queryset=Cluster.objects.all(), required=False, widget=APISelect( api_url='/api/virtualization/clusters/' ) ) role = forms.ModelChoiceField( queryset=DeviceRole.objects.filter( vm_role=True ), required=False, widget=APISelect( api_url="/api/dcim/device-roles/", additional_query_params={ "vm_role": "True" } ) ) tenant = forms.ModelChoiceField( queryset=Tenant.objects.all(), required=False, widget=APISelect( api_url='/api/tenancy/tenants/' ) ) platform = forms.ModelChoiceField( queryset=Platform.objects.all(), required=False, widget=APISelect( api_url='/api/dcim/platforms/' ) ) vcpus = forms.IntegerField( required=False, label='vCPUs' ) memory = forms.IntegerField( required=False, label='Memory (MB)' ) disk = forms.IntegerField( required=False, label='Disk (GB)' ) comments = CommentField( widget=SmallTextarea, label='Comments' ) class Meta: nullable_fields = [ 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments', ]
from utilities.forms import ( APISelect, BootstrapMixin, BulkEditNullBooleanSelect, ChainedModelChoiceField, CSVChoiceField, ExpandableIPAddressField, FilterChoiceField, FlexibleModelChoiceField, Livesearch, ReturnURLForm, SlugField, add_blank_choice, ) from virtualization.models import VirtualMachine from .constants import IPADDRESS_ROLE_CHOICES, IPADDRESS_STATUS_CHOICES, PREFIX_STATUS_CHOICES, VLAN_STATUS_CHOICES from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF IP_FAMILY_CHOICES = [ ('', 'All'), (4, 'IPv4'), (6, 'IPv6'), ] PREFIX_MASK_LENGTH_CHOICES = add_blank_choice([(i, i) for i in range(1, 128)]) IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([(i, i) for i in range(1, 129)]) # # VRFs # class VRFForm(BootstrapMixin, TenancyForm, CustomFieldForm): class Meta: model = VRF fields = ['name', 'rd', 'enforce_unique', 'description', 'tenant_group', 'tenant'] labels = { 'rd': "RD", }
class VMInterfaceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditForm): pk = forms.ModelMultipleChoiceField(queryset=VMInterface.objects.all(), widget=forms.MultipleHiddenInput()) virtual_machine = forms.ModelChoiceField( queryset=VirtualMachine.objects.all(), required=False, disabled=True, widget=forms.HiddenInput()) parent = DynamicModelChoiceField(queryset=VMInterface.objects.all(), required=False) enabled = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect()) mtu = forms.IntegerField(required=False, min_value=INTERFACE_MTU_MIN, max_value=INTERFACE_MTU_MAX, label='MTU') description = forms.CharField(max_length=100, required=False) mode = forms.ChoiceField(choices=add_blank_choice(InterfaceModeChoices), required=False, widget=StaticSelect()) untagged_vlan = DynamicModelChoiceField(queryset=VLAN.objects.all(), required=False) tagged_vlans = DynamicModelMultipleChoiceField(queryset=VLAN.objects.all(), required=False) class Meta: nullable_fields = [ 'parent', 'mtu', 'description', ] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if 'virtual_machine' in self.initial: vm_id = self.initial.get('virtual_machine') # Restrict parent interface assignment by VM self.fields['parent'].widget.add_query_param( 'virtual_machine_id', vm_id) # Limit VLAN choices by virtual machine self.fields['untagged_vlan'].widget.add_query_param( 'available_on_virtualmachine', vm_id) self.fields['tagged_vlans'].widget.add_query_param( 'available_on_virtualmachine', vm_id) else: # See 5643 if 'pk' in self.initial: site = None interfaces = VMInterface.objects.filter( pk__in=self.initial['pk']).prefetch_related( 'virtual_machine__cluster__site') # Check interface sites. First interface should set site, further interfaces will either continue the # loop or reset back to no site and break the loop. for interface in interfaces: if site is None: site = interface.virtual_machine.cluster.site elif interface.virtual_machine.cluster.site is not site: site = None break if site is not None: self.fields['untagged_vlan'].widget.add_query_param( 'site_id', site.pk) self.fields['tagged_vlans'].widget.add_query_param( 'site_id', site.pk)
class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm): model = Prefix field_order = [ 'q', 'within_include', 'family', 'mask_length', 'vrf_id', 'status', 'region', 'site', 'role', 'tenant_group', 'tenant', 'is_pool', 'expand', ] q = forms.CharField(required=False, label='Search') within_include = forms.CharField( required=False, widget=forms.TextInput(attrs={ 'placeholder': 'Prefix', }), label='Search within') family = forms.ChoiceField( required=False, choices=add_blank_choice(IPAddressFamilyChoices), label='Address family', widget=StaticSelect2()) mask_length = forms.ChoiceField(required=False, choices=PREFIX_MASK_LENGTH_CHOICES, label='Mask length', widget=StaticSelect2()) vrf_id = DynamicModelMultipleChoiceField(queryset=VRF.objects.all(), required=False, label='VRF', widget=APISelectMultiple( null_option=True, )) status = forms.MultipleChoiceField(choices=PrefixStatusChoices, required=False, widget=StaticSelect2Multiple()) region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', required=False, widget=APISelectMultiple(value_field="slug", filter_for={'site': 'region'})) site = DynamicModelMultipleChoiceField(queryset=Site.objects.all(), to_field_name='slug', required=False, widget=APISelectMultiple( value_field="slug", null_option=True, )) role = DynamicModelMultipleChoiceField(queryset=Role.objects.all(), to_field_name='slug', required=False, widget=APISelectMultiple( value_field="slug", null_option=True, )) is_pool = forms.NullBooleanField( required=False, label='Is a pool', widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES)) expand = forms.BooleanField(required=False, label='Expand prefix hierarchy') tag = TagFilterField(model)
class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditForm): pk = forms.ModelMultipleChoiceField(queryset=Rack.objects.all(), widget=forms.MultipleHiddenInput) region = DynamicModelChoiceField(queryset=Region.objects.all(), required=False, initial_params={'sites': '$site'}) site_group = DynamicModelChoiceField(queryset=SiteGroup.objects.all(), required=False, initial_params={'sites': '$site'}) site = DynamicModelChoiceField(queryset=Site.objects.all(), required=False, query_params={ 'region_id': '$region', 'group_id': '$site_group', }) location = DynamicModelChoiceField(queryset=Location.objects.all(), required=False, query_params={'site_id': '$site'}) tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False) status = forms.ChoiceField(choices=add_blank_choice(RackStatusChoices), required=False, initial='', widget=StaticSelect()) role = DynamicModelChoiceField(queryset=RackRole.objects.all(), required=False) serial = forms.CharField(max_length=50, required=False, label='Serial Number') asset_tag = forms.CharField(max_length=50, required=False) type = forms.ChoiceField(choices=add_blank_choice(RackTypeChoices), required=False, widget=StaticSelect()) width = forms.ChoiceField(choices=add_blank_choice(RackWidthChoices), required=False, widget=StaticSelect()) u_height = forms.IntegerField(required=False, label='Height (U)') desc_units = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label='Descending units') outer_width = forms.IntegerField(required=False, min_value=1) outer_depth = forms.IntegerField(required=False, min_value=1) outer_unit = forms.ChoiceField( choices=add_blank_choice(RackDimensionUnitChoices), required=False, widget=StaticSelect()) comments = CommentField(widget=SmallTextarea, label='Comments') class Meta: nullable_fields = [ 'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'comments', ]
Livesearch, ReturnURLForm, SlugField, add_blank_choice, ) from virtualization.models import VirtualMachine from .constants import IPADDRESS_ROLE_CHOICES, IPADDRESS_STATUS_CHOICES, PREFIX_STATUS_CHOICES, VLAN_STATUS_CHOICES from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF IP_FAMILY_CHOICES = [ ('', 'All'), (4, 'IPv4'), (6, 'IPv6'), ] PREFIX_MASK_LENGTH_CHOICES = add_blank_choice([(i, i) for i in range(1, 128)]) IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([(i, i) for i in range(1, 129)]) # # VRFs # class VRFForm(BootstrapMixin, TenancyForm, CustomFieldForm): class Meta: model = VRF fields = [ 'name', 'rd', 'enforce_unique', 'description', 'tenant_group', 'tenant' ]
def __init__(self, choices, *args, **kwargs): super().__init__(*args, **kwargs) # Set field choices, adding a blank choice to avoid forced selections self.field_attrs['choices'] = add_blank_choice(choices)