from django import forms from circuits.models import Circuit, CircuitTermination, Provider from dcim.models import * from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField from .models import CableForm def get_cable_form(a_type, b_type): class FormMetaclass(forms.models.ModelFormMetaclass): def __new__(mcs, name, bases, attrs): for cable_end, term_cls in (('a', a_type), ('b', b_type)): attrs[f'termination_{cable_end}_region'] = DynamicModelChoiceField( queryset=Region.objects.all(), label='Region', required=False, initial_params={ 'sites': f'$termination_{cable_end}_site' } ) attrs[f'termination_{cable_end}_sitegroup'] = DynamicModelChoiceField( queryset=SiteGroup.objects.all(), label='Site group', required=False, initial_params={ 'sites': f'$termination_{cable_end}_site' } ) attrs[f'termination_{cable_end}_site'] = DynamicModelChoiceField( queryset=Site.objects.all(), label='Site', required=False, query_params={ 'region_id': f'$termination_{cable_end}_region', 'group_id': f'$termination_{cable_end}_sitegroup', } ) attrs[f'termination_{cable_end}_location'] = DynamicModelChoiceField( queryset=Location.objects.all(), label='Location', required=False, null_option='None', query_params={ 'site_id': f'$termination_{cable_end}_site' } ) # Device component if hasattr(term_cls, 'device'): attrs[f'termination_{cable_end}_rack'] = DynamicModelChoiceField( queryset=Rack.objects.all(), label='Rack', required=False, null_option='None', initial_params={ 'devices': f'$termination_{cable_end}_device' }, query_params={ 'site_id': f'$termination_{cable_end}_site', 'location_id': f'$termination_{cable_end}_location', } ) attrs[f'termination_{cable_end}_device'] = DynamicModelChoiceField( queryset=Device.objects.all(), label='Device', required=False, initial_params={ f'{term_cls._meta.model_name}s__in': f'${cable_end}_terminations' }, query_params={ 'site_id': f'$termination_{cable_end}_site', 'location_id': f'$termination_{cable_end}_location', 'rack_id': f'$termination_{cable_end}_rack', } ) attrs[f'{cable_end}_terminations'] = DynamicModelMultipleChoiceField( queryset=term_cls.objects.all(), label=term_cls._meta.verbose_name.title(), disabled_indicator='_occupied', query_params={ 'device_id': f'termination_{cable_end}_device', } ) # PowerFeed elif term_cls == PowerFeed: attrs[f'termination_{cable_end}_powerpanel'] = DynamicModelChoiceField( queryset=PowerPanel.objects.all(), label='Power Panel', required=False, initial_params={ 'powerfeeds__in': f'${cable_end}_terminations' }, query_params={ 'site_id': f'$termination_{cable_end}_site', 'location_id': f'$termination_{cable_end}_location', } ) attrs[f'{cable_end}_terminations'] = DynamicModelMultipleChoiceField( queryset=term_cls.objects.all(), label='Power Feed', disabled_indicator='_occupied', query_params={ 'powerpanel_id': f'termination_{cable_end}_powerpanel', } ) # CircuitTermination elif term_cls == CircuitTermination: attrs[f'termination_{cable_end}_provider'] = DynamicModelChoiceField( queryset=Provider.objects.all(), label='Provider', initial_params={ 'circuits': f'$termination_{cable_end}_circuit' }, required=False ) attrs[f'termination_{cable_end}_circuit'] = DynamicModelChoiceField( queryset=Circuit.objects.all(), label='Circuit', initial_params={ 'terminations__in': f'${cable_end}_terminations' }, query_params={ 'provider_id': f'$termination_{cable_end}_provider', 'site_id': f'$termination_{cable_end}_site', } ) attrs[f'{cable_end}_terminations'] = DynamicModelMultipleChoiceField( queryset=term_cls.objects.all(), label='Side', disabled_indicator='_occupied', query_params={ 'circuit_id': f'termination_{cable_end}_circuit', } ) return super().__new__(mcs, name, bases, attrs) class _CableForm(CableForm, metaclass=FormMetaclass): def __init__(self, *args, **kwargs): # TODO: Temporary hack to work around list handling limitations with utils.normalize_querydict() for field_name in ('a_terminations', 'b_terminations'): if field_name in kwargs.get('initial', {}) and type(kwargs['initial'][field_name]) is not list: kwargs['initial'][field_name] = [kwargs['initial'][field_name]] super().__init__(*args, **kwargs) if self.instance and self.instance.pk: # Initialize A/B terminations when modifying an existing Cable instance self.initial['a_terminations'] = self.instance.get_a_terminations() self.initial['b_terminations'] = self.instance.get_b_terminations() def save(self, *args, **kwargs): # Set the A/B terminations on the Cable instance self.instance.a_terminations = self.cleaned_data['a_terminations'] self.instance.b_terminations = self.cleaned_data['b_terminations'] return super().save(*args, **kwargs) return _CableForm