class PowerFeedBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm): pk = forms.ModelMultipleChoiceField(queryset=PowerFeed.objects.all(), widget=forms.MultipleHiddenInput) power_panel = DynamicModelChoiceField(queryset=PowerPanel.objects.all(), required=False) rack = DynamicModelChoiceField( queryset=Rack.objects.all(), required=False, ) status = forms.ChoiceField( choices=add_blank_choice(PowerFeedStatusChoices), required=False, initial='', widget=StaticSelect()) type = forms.ChoiceField(choices=add_blank_choice(PowerFeedTypeChoices), required=False, initial='', widget=StaticSelect()) supply = forms.ChoiceField( choices=add_blank_choice(PowerFeedSupplyChoices), required=False, initial='', widget=StaticSelect()) phase = forms.ChoiceField(choices=add_blank_choice(PowerFeedPhaseChoices), required=False, initial='', widget=StaticSelect()) voltage = forms.IntegerField(required=False) amperage = forms.IntegerField(required=False) max_utilization = forms.IntegerField(required=False) mark_connected = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect) comments = CommentField(widget=SmallTextarea, label='Comments') class Meta: nullable_fields = [ 'location', 'comments', ]
class ProviderNetworkBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditForm): pk = forms.ModelMultipleChoiceField( queryset=ProviderNetwork.objects.all(), widget=forms.MultipleHiddenInput ) provider = DynamicModelChoiceField( queryset=Provider.objects.all(), required=False ) description = forms.CharField( max_length=100, required=False ) comments = CommentField( widget=SmallTextarea, label='Comments' ) class Meta: nullable_fields = [ 'description', 'comments', ]
class ClusterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm): pk = forms.ModelMultipleChoiceField( queryset=Cluster.objects.all(), widget=forms.MultipleHiddenInput() ) type = DynamicModelChoiceField( queryset=ClusterType.objects.all(), required=False ) group = DynamicModelChoiceField( queryset=ClusterGroup.objects.all(), required=False ) tenant = DynamicModelChoiceField( queryset=Tenant.objects.all(), required=False ) region = DynamicModelChoiceField( queryset=Region.objects.all(), required=False, to_field_name='slug' ) site = DynamicModelChoiceField( queryset=Site.objects.all(), required=False, query_params={ 'region': '$region' } ) comments = CommentField( widget=SmallTextarea, label='Comments' ) class Meta: nullable_fields = [ 'group', 'site', 'comments', 'tenant', ]
class ClusterForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): type = DynamicModelChoiceField(queryset=ClusterType.objects.all()) group = DynamicModelChoiceField(queryset=ClusterGroup.objects.all(), required=False) 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', }) comments = CommentField() tags = DynamicModelMultipleChoiceField(queryset=Tag.objects.all(), required=False) class Meta: model = Cluster fields = ( 'name', 'type', 'group', 'tenant', 'region', 'site_group', 'site', 'comments', 'tags', ) fieldsets = ( ('Cluster', ('name', 'type', 'group', 'region', 'site_group', 'site', 'tags')), ('Tenancy', ('tenant_group', 'tenant')), )
class ClusterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm): pk = forms.ModelMultipleChoiceField(queryset=Cluster.objects.all(), widget=forms.MultipleHiddenInput()) type = forms.ModelChoiceField( queryset=ClusterType.objects.all(), required=False, widget=APISelect(api_url="/api/virtualization/cluster-types/")) group = forms.ModelChoiceField( queryset=ClusterGroup.objects.all(), required=False, widget=APISelect(api_url="/api/virtualization/cluster-groups/")) site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False, widget=APISelect(api_url="/api/dcim/sites/")) comments = CommentField(widget=SmallTextarea()) class Meta: nullable_fields = [ 'group', 'site', 'comments', ]
class ClusterForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): type = DynamicModelChoiceField( queryset=ClusterType.objects.all() ) group = DynamicModelChoiceField( queryset=ClusterGroup.objects.all(), required=False ) site = DynamicModelChoiceField( queryset=Site.objects.all(), required=False ) comments = CommentField() tags = DynamicModelMultipleChoiceField( queryset=Tag.objects.all(), required=False ) class Meta: model = Cluster fields = ( 'name', 'type', 'group', 'tenant', 'site', 'comments', 'tags', )
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 ProviderBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm): pk = forms.ModelMultipleChoiceField( queryset=Provider.objects.all(), widget=forms.MultipleHiddenInput ) asn = forms.IntegerField( required=False, label='ASN' ) account = forms.CharField( max_length=30, required=False, label='Account number' ) portal_url = forms.URLField( required=False, label='Portal' ) noc_contact = forms.CharField( required=False, widget=SmallTextarea, label='NOC contact' ) admin_contact = forms.CharField( required=False, widget=SmallTextarea, label='Admin contact' ) comments = CommentField( widget=SmallTextarea, label='Comments' ) class Meta: nullable_fields = [ 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments', ]
class CircuitForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): provider = DynamicModelChoiceField(queryset=Provider.objects.all()) type = DynamicModelChoiceField(queryset=CircuitType.objects.all()) comments = CommentField() tags = DynamicModelMultipleChoiceField(queryset=Tag.objects.all(), required=False) class Meta: model = Circuit fields = [ 'cid', 'type', 'provider', 'status', 'install_date', 'commit_rate', 'description', 'tenant_group', 'tenant', 'comments', 'tags', ] fieldsets = ( ('Circuit', ('provider', 'cid', 'type', 'status', 'install_date', 'commit_rate', 'description', 'tags')), ('Tenancy', ('tenant_group', 'tenant')), ) help_texts = { 'cid': "Unique circuit ID", 'commit_rate': "Committed rate", } widgets = { 'status': StaticSelect(), 'install_date': DatePicker(), 'commit_rate': SelectSpeedWidget(), }
class CircuitForm(BootstrapMixin, TenancyForm, CustomFieldForm): comments = CommentField() tags = TagField(required=False) class Meta: model = Circuit fields = [ 'cid', 'type', 'provider', 'status', 'install_date', 'commit_rate', 'description', 'tenant_group', 'tenant', 'comments', 'tags', ] help_texts = { 'cid': "Unique circuit ID", 'install_date': "Format: YYYY-MM-DD", 'commit_rate': "Committed rate", }
class ContactForm(CustomFieldModelForm): group = DynamicModelChoiceField(queryset=ContactGroup.objects.all(), required=False) comments = CommentField() tags = DynamicModelMultipleChoiceField(queryset=Tag.objects.all(), required=False) class Meta: model = Contact fields = ( 'group', 'name', 'title', 'phone', 'email', 'address', 'comments', 'tags', ) fieldsets = (('Contact', ('group', 'name', 'title', 'phone', 'email', 'address', 'tags')), ) widgets = { 'address': SmallTextarea(attrs={'rows': 3}), }
class RackForm(forms.ModelForm, BootstrapMixin): group = forms.ModelChoiceField( queryset=RackGroup.objects.all(), required=False, label='Group', widget=APISelect(api_url='/api/dcim/rack-groups/?site_id={{site}}', )) comments = CommentField() class Meta: model = Rack fields = [ 'site', 'group', 'name', 'facility_id', 'u_height', 'comments' ] help_texts = { 'site': "The site at which the rack exists", 'name': "Organizational rack name", 'facility_id': "The unique rack ID assigned by the facility", 'u_height': "Height in rack units", } widgets = { 'site': forms.Select(attrs={'filter-for': 'group'}), } def __init__(self, *args, **kwargs): super(RackForm, self).__init__(*args, **kwargs) # Limit rack group choices if self.is_bound and self.data.get('site'): self.fields['group'].queryset = RackGroup.objects.filter( site__pk=self.data['site']) elif self.initial.get('site'): self.fields['group'].queryset = RackGroup.objects.filter( site=self.initial['site']) else: self.fields['group'].choices = []
class ClusterForm(BootstrapMixin, CustomFieldForm): comments = CommentField( widget=SmallTextarea() ) tags = TagField( required=False ) class Meta: model = Cluster fields = [ '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 ClusterForm(BootstrapMixin, CustomFieldForm): comments = CommentField(widget=SmallTextarea) class Meta: model = Cluster fields = ['name', 'type', 'group', 'site', 'comments']
class CircuitForm(forms.ModelForm, BootstrapMixin): site = forms.ModelChoiceField( queryset=Site.objects.all(), widget=forms.Select(attrs={'filter-for': 'rack'})) rack = forms.ModelChoiceField( queryset=Rack.objects.all(), required=False, label='Rack', widget=APISelect(api_url='/api/dcim/racks/?site_id={{site}}', attrs={'filter-for': 'device'})) device = forms.ModelChoiceField( queryset=Device.objects.all(), required=False, label='Device', widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}', attrs={'filter-for': 'interface'})) livesearch = forms.CharField(required=False, label='Device', widget=Livesearch( query_key='q', query_url='dcim-api:device_list', field_to_update='device')) interface = forms.ModelChoiceField( queryset=Interface.objects.all(), required=False, label='Interface', widget=APISelect( api_url='/api/dcim/devices/{{device}}/interfaces/?type=physical', disabled_indicator='is_connected')) comments = CommentField() class Meta: model = Circuit fields = [ 'cid', 'type', 'provider', 'tenant', 'site', 'rack', 'device', 'livesearch', 'interface', 'install_date', 'port_speed', 'upstream_speed', 'commit_rate', 'xconnect_id', 'pp_info', 'comments' ] help_texts = { 'cid': "Unique circuit ID", 'install_date': "Format: YYYY-MM-DD", 'port_speed': "Physical circuit speed", 'commit_rate': "Commited rate", 'xconnect_id': "ID of the local cross-connect", 'pp_info': "Patch panel ID and port number(s)" } def __init__(self, *args, **kwargs): super(CircuitForm, self).__init__(*args, **kwargs) # If this circuit has been assigned to an interface, initialize rack and device if self.instance.interface: self.initial['rack'] = self.instance.interface.device.rack self.initial['device'] = self.instance.interface.device # Limit rack choices if self.is_bound: self.fields['rack'].queryset = Rack.objects.filter( site__pk=self.data['site']) elif self.initial.get('site'): self.fields['rack'].queryset = Rack.objects.filter( site=self.initial['site']) else: self.fields['rack'].choices = [] # Limit device choices if self.is_bound and self.data.get('rack'): self.fields['device'].queryset = Device.objects.filter( rack=self.data['rack']) elif self.initial.get('rack'): self.fields['device'].queryset = Device.objects.filter( rack=self.initial['rack']) else: self.fields['device'].choices = [] # Limit interface choices if self.is_bound and self.data.get('device'): interfaces = Interface.objects.filter(device=self.data['device'])\ .exclude(form_factor=IFACE_FF_VIRTUAL).select_related('circuit', 'connected_as_a', 'connected_as_b') self.fields['interface'].widget.attrs['initial'] = self.data.get( 'interface') elif self.initial.get('device'): interfaces = Interface.objects.filter(device=self.initial['device'])\ .exclude(form_factor=IFACE_FF_VIRTUAL).select_related('circuit', 'connected_as_a', 'connected_as_b') self.fields['interface'].widget.attrs[ 'initial'] = self.initial.get('interface') else: interfaces = [] self.fields['interface'].choices = [(iface.id, { 'label': iface.name, 'disabled': iface.is_connected and iface.id != self.fields['interface'].widget.attrs.get('initial'), }) for iface in interfaces]
class DeviceForm(TenancyForm, CustomFieldModelForm): 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(), query_params={ 'region_id': '$region', 'group_id': '$site_group', }) location = DynamicModelChoiceField(queryset=Location.objects.all(), required=False, query_params={'site_id': '$site'}, initial_params={'racks': '$rack'}) rack = DynamicModelChoiceField(queryset=Rack.objects.all(), required=False, query_params={ 'site_id': '$site', 'location_id': '$location', }) position = forms.IntegerField( required=False, help_text="The lowest-numbered unit occupied by the device", widget=APISelect(api_url='/api/dcim/racks/{{rack}}/elevation/', attrs={ 'disabled-indicator': 'device', 'data-dynamic-params': '[{"fieldName":"face","queryParam":"face"}]' })) manufacturer = DynamicModelChoiceField( queryset=Manufacturer.objects.all(), required=False, initial_params={'device_types': '$device_type'}) device_type = DynamicModelChoiceField( queryset=DeviceType.objects.all(), query_params={'manufacturer_id': '$manufacturer'}) device_role = DynamicModelChoiceField(queryset=DeviceRole.objects.all()) platform = DynamicModelChoiceField( queryset=Platform.objects.all(), required=False, query_params={'manufacturer_id': ['$manufacturer', 'null']}) cluster_group = DynamicModelChoiceField( queryset=ClusterGroup.objects.all(), required=False, null_option='None', initial_params={'clusters': '$cluster'}) cluster = DynamicModelChoiceField( queryset=Cluster.objects.all(), required=False, query_params={'group_id': '$cluster_group'}) comments = CommentField() local_context_data = JSONField(required=False, label='') tags = DynamicModelMultipleChoiceField(queryset=Tag.objects.all(), required=False) class Meta: model = Device fields = [ 'name', 'device_role', 'device_type', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'rack', 'location', 'position', 'face', 'status', 'airflow', 'platform', 'primary_ip4', 'primary_ip6', 'cluster_group', 'cluster', 'tenant_group', 'tenant', 'comments', 'tags', 'local_context_data' ] help_texts = { 'device_role': "The function this device serves", 'serial': "Chassis serial number", 'local_context_data': "Local config context data overwrites all source contexts in the final rendered " "config context", } widgets = { 'face': StaticSelect(), 'status': StaticSelect(), 'airflow': StaticSelect(), 'primary_ip4': StaticSelect(), 'primary_ip6': StaticSelect(), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if self.instance.pk: # Compile list of choices for primary IPv4 and IPv6 addresses for family in [4, 6]: ip_choices = [(None, '---------')] # Gather PKs of all interfaces belonging to this Device or a peer VirtualChassis member interface_ids = self.instance.vc_interfaces( if_master=False).values_list('pk', flat=True) # Collect interface IPs interface_ips = IPAddress.objects.filter( address__family=family, assigned_object_type=ContentType.objects.get_for_model( Interface), assigned_object_id__in=interface_ids).prefetch_related( 'assigned_object') if interface_ips: ip_list = [(ip.id, f'{ip.address} ({ip.assigned_object})') for ip in interface_ips] ip_choices.append(('Interface IPs', ip_list)) # Collect NAT IPs nat_ips = IPAddress.objects.prefetch_related( 'nat_inside').filter( address__family=family, nat_inside__assigned_object_type=ContentType.objects. get_for_model(Interface), nat_inside__assigned_object_id__in=interface_ids ).prefetch_related('assigned_object') if nat_ips: ip_list = [(ip.id, f'{ip.address} (NAT)') for ip in nat_ips] ip_choices.append(('NAT IPs', ip_list)) self.fields['primary_ip{}'.format(family)].choices = ip_choices # If editing an existing device, exclude it from the list of occupied rack units. This ensures that a device # can be flipped from one face to another. self.fields['position'].widget.add_query_param( 'exclude', self.instance.pk) # Limit platform by manufacturer self.fields['platform'].queryset = Platform.objects.filter( Q(manufacturer__isnull=True) | Q(manufacturer=self.instance.device_type.manufacturer)) # Disable rack assignment if this is a child device installed in a parent device if self.instance.device_type.is_child_device and hasattr( self.instance, 'parent_bay'): self.fields['site'].disabled = True self.fields['rack'].disabled = True self.initial['site'] = self.instance.parent_bay.device.site_id self.initial['rack'] = self.instance.parent_bay.device.rack_id else: # An object that doesn't exist yet can't have any IPs assigned to it self.fields['primary_ip4'].choices = [] self.fields['primary_ip4'].widget.attrs['readonly'] = True self.fields['primary_ip6'].choices = [] self.fields['primary_ip6'].widget.attrs['readonly'] = True # Rack position position = self.data.get('position') or self.initial.get('position') if position: self.fields['position'].widget.choices = [(position, f'U{position}')]
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 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', ]
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', ]
class RackBulkEditForm(forms.Form, BootstrapMixin): pk = forms.ModelMultipleChoiceField(queryset=Rack.objects.all(), widget=forms.MultipleHiddenInput) site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False) group = forms.ModelChoiceField(queryset=RackGroup.objects.all(), required=False) u_height = forms.IntegerField(required=False, label='Height (U)') comments = CommentField()
class DeviceForm(forms.ModelForm, BootstrapMixin): site = forms.ModelChoiceField( queryset=Site.objects.all(), widget=forms.Select(attrs={'filter-for': 'rack'})) rack = forms.ModelChoiceField( queryset=Rack.objects.all(), widget=APISelect(api_url='/api/dcim/racks/?site_id={{site}}', display_field='display_name', attrs={'filter-for': 'position'})) position = forms.TypedChoiceField( required=False, empty_value=None, widget=APISelect( api_url='/api/dcim/racks/{{rack}}/rack-units/?face={{face}}', disabled_indicator='device', )) manufacturer = forms.ModelChoiceField( queryset=Manufacturer.objects.all(), widget=forms.Select(attrs={'filter-for': 'device_type'})) device_type = forms.ModelChoiceField( queryset=DeviceType.objects.all(), label='Model', widget=APISelect( api_url='/api/dcim/device-types/?manufacturer_id={{manufacturer}}', display_field='model')) comments = CommentField() class Meta: model = Device fields = [ 'name', 'device_role', 'device_type', 'serial', 'site', 'rack', 'position', 'face', 'status', 'platform', 'primary_ip', 'comments' ] help_texts = { 'device_role': "The function this device serves", 'serial': "Chassis serial number", } widgets = { 'face': forms.Select(attrs={'filter-for': 'position'}), 'manufacturer': forms.Select(attrs={'filter-for': 'device_type'}), } def __init__(self, *args, **kwargs): super(DeviceForm, self).__init__(*args, **kwargs) if self.instance.pk: # Initialize helper selections self.initial['site'] = self.instance.rack.site self.initial[ 'manufacturer'] = self.instance.device_type.manufacturer # Compile list of IPs assigned to this device primary_ip_choices = [] interface_ips = IPAddress.objects.filter( interface__device=self.instance) primary_ip_choices += [(ip.id, '{} ({})'.format(ip.address, ip.interface)) for ip in interface_ips] nat_ips = IPAddress.objects.filter(nat_inside__interface__device=self.instance)\ .select_related('nat_inside__interface') primary_ip_choices += [ (ip.id, '{} ({} NAT)'.format(ip.address, ip.nat_inside.interface)) for ip in nat_ips ] self.fields['primary_ip'].choices = [(None, '---------') ] + primary_ip_choices else: # An object that doesn't exist yet can't have any IPs assigned to it self.fields['primary_ip'].choices = [] self.fields['primary_ip'].widget.attrs['readonly'] = True # Limit rack choices if self.is_bound: self.fields['rack'].queryset = Rack.objects.filter( site__pk=self.data['site']) elif self.initial.get('site'): self.fields['rack'].queryset = Rack.objects.filter( site=self.initial['site']) else: self.fields['rack'].choices = [] # Rack position try: if self.is_bound and self.data.get('rack') and str( self.data.get('face')): position_choices = Rack.objects.get( pk=self.data['rack']).get_rack_units( face=self.data.get('face')) elif self.initial.get('rack') and str(self.initial.get('face')): position_choices = Rack.objects.get( pk=self.initial['rack']).get_rack_units( face=self.initial.get('face')) else: position_choices = [] except Rack.DoesNotExist: position_choices = [] self.fields['position'].choices = [('', '---------')] + [(p['id'], { 'label': p['name'], 'disabled': bool(p['device'] and p['id'] != self.initial.get('position')), }) for p in position_choices] # Limit device_type choices if self.is_bound: self.fields['device_type'].queryset = DeviceType.objects.filter(manufacturer__pk=self.data['manufacturer'])\ .select_related('manufacturer') elif self.initial.get('manufacturer'): self.fields['device_type'].queryset = DeviceType.objects.filter(manufacturer=self.initial['manufacturer'])\ .select_related('manufacturer') else: self.fields['device_type'].choices = []