class OrganizationForm(forms.ModelForm): """Form for editing an organization""" parent = forms.ChoiceField(required=False) data = HStoreField(label='Attributes', required=False) class Meta(object): model = Organization fields = '__all__' def __init__(self, *args, **kwargs): super(OrganizationForm, self).__init__(*args, **kwargs) field = self.fields['parent'] field.choices = create_hierarchy(Organization) if self.instance.id: # disallow editing the primary key of existing record del self.fields['id'] # remove self and all descendants from list of selectable parents field.choices = cut_branch(field, Organization, self.instance.id) def clean_parent(self): """Provide a model as the parent. This is needed because we use a normal ChoiceField (because of the tree structure) that does not provide a model instance when selected. """ parent = self.cleaned_data.get('parent') if parent: return Organization.objects.get(pk=parent) else: # Explicitly return None because no parent is an empty string and # thus we need to return None, not the empty string return None
class RoomForm(forms.ModelForm): """Form for editing/adding rooms""" location = forms.ChoiceField(choices=()) data = HStoreField(label='Attributes', required=False) def __init__(self, *args, **kwargs): super(RoomForm, self).__init__(*args, **kwargs) self.fields['location'].choices = create_hierarchy(Location) if self.instance and self.instance.pk: self.fields['id'].widget.attrs['readonly'] = True class Meta(object): model = Room fields = '__all__' def clean_location(self): data = self.cleaned_data.get('location') return Location.objects.get(pk=data)
class NetboxModelForm(forms.ModelForm): """Modelform for netbox for use in SeedDB""" ip = forms.CharField() function = forms.CharField(required=False) data = HStoreField(label='Attributes', required=False) sysname = forms.CharField(required=False) virtual_instance = MyModelMultipleChoiceField( queryset=Netbox.objects.none(), required=False, label='Virtual instances', help_text='The list of virtual instances inside this master device') class Meta(object): model = Netbox fields = ['ip', 'room', 'category', 'organization', 'groups', 'sysname', 'type', 'data', 'master', 'virtual_instance', 'profiles'] help_texts = { 'master': 'Select a master device when this IP Device is a virtual' ' instance' } def __init__(self, *args, **kwargs): super(NetboxModelForm, self).__init__(*args, **kwargs) self.fields['organization'].choices = create_hierarchy(Organization) # Master and instance related queries masters = [n.master.pk for n in Netbox.objects.filter(master__isnull=False)] self.fields['master'].queryset = self.create_master_query(masters) self.fields['virtual_instance'].queryset = self.create_instance_query(masters) if self.instance.pk: # Set instances that we are master to as initial values self.initial['virtual_instance'] = Netbox.objects.filter( master=self.instance) # Disable fields based on current state if self.instance.master: self.fields['virtual_instance'].widget.attrs['disabled'] = True if self.instance.pk in masters: self.fields['master'].widget.attrs['disabled'] = True # Set the inital value of the function field try: netboxinfo = self.instance.info_set.get(variable='function') except NetboxInfo.DoesNotExist: pass else: self.fields['function'].initial = netboxinfo.value css_class = 'large-4' self.helper = FormHelper() self.helper.form_action = '' self.helper.form_method = 'POST' self.helper.form_id = 'seeddb-netbox-form' self.helper.form_tag = False self.helper.layout = Layout( Row( Column( Fieldset('Inventory', 'ip', Div(id='verify-address-feedback'), 'room', 'category', 'organization'), css_class=css_class), Column( Fieldset('Management profiles', Field('profiles', css_class='select2'), NavButton('check_connectivity', 'Check connectivity', css_class='check_connectivity')), Fieldset('Collected info', Div('sysname', 'type', css_class='hide', css_id='real_collected_fields')), css_class=css_class), Column( Fieldset( 'Meta information', 'function', Field('groups', css_class='select2'), 'data', HTML("<a class='advanced-toggle'><i class='fa fa-caret-square-o-right'> </i>Advanced options</a>"), Div( HTML('<small class="alert-box">NB: An IP Device cannot both have a master and have virtual instances</small>'), 'master', 'virtual_instance', css_class='advanced' ) ), css_class=css_class), ), ) def create_instance_query(self, masters): """Creates query for virtual instance multiselect""" # - Should not see other masters # - Should see those we are master for # - Should see those who have no master queryset = Netbox.objects.exclude(pk__in=masters).filter( Q(master=self.instance.pk) | Q(master__isnull=True)) if self.instance.pk: queryset = queryset.exclude(pk=self.instance.pk) return queryset def create_master_query(self, masters): """Creates query for master dropdown list""" # - Should not set those who have master as master queryset = Netbox.objects.filter(master__isnull=True) if self.instance.pk: queryset = queryset.exclude(pk=self.instance.pk) return queryset def clean_ip(self): """Make sure IP-address is valid""" name = self.cleaned_data['ip'].strip() try: ip, _ = resolve_ip_and_sysname(name) except SocketError: raise forms.ValidationError("Could not resolve name %s" % name) return six.text_type(ip) def clean_sysname(self): """Resolve sysname if not set""" sysname = self.cleaned_data.get('sysname') ip = self.cleaned_data.get('ip') if ip and not sysname: _, sysname = resolve_ip_and_sysname(ip) return sysname def clean(self): """Make sure that categories that require communities has that""" cleaned_data = self.cleaned_data ip = cleaned_data.get('ip') cat = cleaned_data.get('category') profiles = cleaned_data.get('profiles') _logger.warning("cleaning profiles: %r", profiles) if ip: try: self._check_existing_ip(ip) except IPExistsException as error: self._errors['ip'] = self.error_class(error.message_list) del cleaned_data['ip'] if cat and cat.req_mgmt and not profiles: self._errors['profiles'] = self.error_class( ["Category %s requires a management profile." % cat.id]) del cleaned_data['profiles'] return cleaned_data def _check_existing_ip(self, ip): msg = [] _, sysname = resolve_ip_and_sysname(ip) if does_ip_exist(ip, self.instance.pk): msg.append("IP (%s) is already in database" % ip) if does_sysname_exist(sysname, self.instance.pk): msg.append("Sysname (%s) is already in database" % sysname) if msg: raise IPExistsException(msg) def save(self, commit=True): netbox = super(NetboxModelForm, self).save(commit) instances = self.cleaned_data.get('virtual_instance') # Clean up instances Netbox.objects.filter( master=netbox).exclude(pk__in=instances).update(master=None) # Add new instances for instance in instances: instance.master = netbox instance.save() return netbox