diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 1fdd304f5..c847f1e41 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -5,7 +5,6 @@ import re from django import forms from django.contrib.postgres.forms.array import SimpleArrayField -from django.core.exceptions import ValidationError from django.db.models import Count, Q from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm @@ -228,14 +227,9 @@ class RackCSVForm(forms.ModelForm): 'invalid_choice': 'Site not found.', } ) - group = forms.ModelChoiceField( - queryset=RackGroup.objects.all(), - to_field_name='name', - required=False, - help_text='Name of parent rack group', - error_messages={ - 'invalid_choice': 'Rack group not found.', - } + group_name = forms.CharField( + help_text='Name of rack group', + required=False ) tenant = forms.ModelChoiceField( queryset=Tenant.objects.all(), @@ -274,13 +268,19 @@ class RackCSVForm(forms.ModelForm): 'site', 'group', 'name', 'facility_id', 'tenant', 'role', 'type', 'width', 'u_height', 'desc_units', ] - def clean_group(self): + def clean(self): + + super(RackCSVForm, self).clean() site = self.cleaned_data.get('site') - group = self.cleaned_data.get('group') + group_name = self.cleaned_data.get('group_name') - if group and group.site != site: - raise ValidationError("Invalid group for site {}: {}".format(site, group)) + # Validate rack group + if group_name: + try: + self.instance.group = RackGroup.objects.get(site=site, name=group_name) + except RackGroup.DoesNotExist: + raise forms.ValidationError("Rack group {} not found for site {}".format(group_name, site)) class RackBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm): @@ -733,6 +733,8 @@ class BaseDeviceCSVForm(forms.ModelForm): def clean(self): + super(BaseDeviceCSVForm, self).clean() + manufacturer = self.cleaned_data.get('manufacturer') model_name = self.cleaned_data.get('model_name') @@ -741,7 +743,7 @@ class BaseDeviceCSVForm(forms.ModelForm): try: self.instance.device_type = DeviceType.objects.get(manufacturer=manufacturer, model=model_name) except DeviceType.DoesNotExist: - self.add_error('model_name', "Invalid device type ({} {})".format(manufacturer, model_name)) + raise forms.ValidationError("Device type {} {} not found".format(manufacturer, model_name)) class DeviceCSVForm(BaseDeviceCSVForm): @@ -753,6 +755,10 @@ class DeviceCSVForm(BaseDeviceCSVForm): 'invalid_choice': 'Invalid site name.', } ) + rack_group = forms.CharField( + required=False, + help_text='Name of parent rack\'s group' + ) rack_name = forms.CharField( required=False, help_text='Name of parent rack' @@ -766,7 +772,7 @@ class DeviceCSVForm(BaseDeviceCSVForm): class Meta(BaseDeviceCSVForm.Meta): fields = [ 'name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'asset_tag', 'status', - 'site', 'rack_name', 'position', 'face', + 'site', 'rack_group', 'rack_name', 'position', 'face', ] def clean(self): @@ -774,26 +780,20 @@ class DeviceCSVForm(BaseDeviceCSVForm): super(DeviceCSVForm, self).clean() site = self.cleaned_data.get('site') + rack_group = self.cleaned_data.get('rack_group') rack_name = self.cleaned_data.get('rack_name') # Validate rack - if site and rack_name: + if site and rack_group and rack_name: try: - self.instance.rack = Rack.objects.get(site=site, name=rack_name) + self.instance.rack = Rack.objects.get(site=site, group__name=rack_group, name=rack_name) except Rack.DoesNotExist: - self.add_error('rack_name', "Invalid rack ({})".format(rack_name)) - - def clean_face(self): - face = self.cleaned_data['face'] - if not face: - return None - try: - return { - 'front': 0, - 'rear': 1, - }[face.lower()] - except KeyError: - raise forms.ValidationError('Invalid rack face ({}); must be "front" or "rear".'.format(face)) + raise forms.ValidationError("Rack {} not found in site {} group {}".format(rack_name, site, rack_group)) + elif site and rack_name: + try: + self.instance.rack = Rack.objects.get(site=site, group__isnull=True, name=rack_name) + except Rack.DoesNotExist: + raise forms.ValidationError("Rack {} not found in site {} (no group)".format(rack_name, site)) class ChildDeviceCSVForm(BaseDeviceCSVForm): @@ -825,13 +825,7 @@ class ChildDeviceCSVForm(BaseDeviceCSVForm): # Validate device bay if parent and device_bay_name: try: - device_bay = DeviceBay.objects.get(device=parent, name=device_bay_name) - if device_bay.installed_device: - self.add_error( - 'device_bay_name', "Device bay ({} {}) is already occupied".format(parent, device_bay_name) - ) - else: - self.instance.parent_bay = device_bay + self.instance.parent_bay = DeviceBay.objects.get(device=parent, name=device_bay_name) except DeviceBay.DoesNotExist: self.add_error( 'device_bay_name', "Parent device/bay ({} {}) not found".format(parent, device_bay_name) diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index d2c45e405..0ea10c838 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -1,7 +1,6 @@ from __future__ import unicode_literals from django import forms -from django.core.exceptions import ValidationError from django.db.models import Count from dcim.models import Site, Rack, Device, Interface @@ -230,7 +229,7 @@ class PrefixCSVForm(forms.ModelForm): 'invalid_choice': 'Site not found.', } ) - vlan_group_name = forms.CharField( + vlan_group = forms.CharField( help_text='Group name of assigned VLAN', required=False ) @@ -255,40 +254,36 @@ class PrefixCSVForm(forms.ModelForm): class Meta: model = Prefix fields = [ - 'prefix', 'vrf', 'tenant', 'site', 'vlan_group_name', 'vlan_vid', 'status', 'role', 'is_pool', - 'description', + 'prefix', 'vrf', 'tenant', 'site', 'vlan_group', 'vlan_vid', 'status', 'role', 'is_pool', 'description', ] def clean(self): - site = self.cleaned_data.get('site') - vlan_group_name = self.cleaned_data.get('vlan_group_name') - vlan_vid = self.cleaned_data.get('vlan_vid') - vlan_group = None + super(PrefixCSVForm, self).clean() - # Validate VLAN group - if vlan_group_name: - try: - vlan_group = VLANGroup.objects.get(site=site, name=vlan_group_name) - except VLANGroup.DoesNotExist: - if site: - self.add_error('vlan_group_name', "Invalid VLAN group ({} - {}).".format(site, vlan_group_name)) - else: - self.add_error('vlan_group_name', "Invalid global VLAN group ({}).".format(vlan_group_name)) + site = self.cleaned_data.get('site') + vlan_group = self.cleaned_data.get('vlan_group') + vlan_vid = self.cleaned_data.get('vlan_vid') # Validate VLAN - if vlan_vid: + if vlan_group and vlan_vid: try: - self.instance.vlan = VLAN.objects.get(site=site, group=vlan_group, vid=vlan_vid) + self.instance.vlan = VLAN.objects.get(site=site, group__name=vlan_group, vid=vlan_vid) except VLAN.DoesNotExist: if site: - self.add_error('vlan_vid', "Invalid VLAN ID ({}) for site {}.".format(vlan_vid, site)) - elif vlan_group: - self.add_error('vlan_vid', "Invalid VLAN ID ({}) for group {}.".format(vlan_vid, vlan_group_name)) - elif not vlan_group_name: - self.add_error('vlan_vid', "Invalid global VLAN ID ({}).".format(vlan_vid)) - except VLAN.MultipleObjectsReturned: - self.add_error('vlan_vid', "Multiple VLANs found ({} - VID {})".format(site, vlan_vid)) + raise forms.ValidationError("VLAN {} not found in site {} group {}".format( + vlan_vid, site, vlan_group + )) + else: + raise forms.ValidationError("Global VLAN {} not found in group {}".format(vlan_vid, vlan_group)) + elif vlan_vid: + try: + self.instance.vlan = VLAN.objects.get(site=site, group__isnull=True, vid=vlan_vid) + except VLAN.DoesNotExist: + if site: + raise forms.ValidationError("VLAN {} not found in site {}".format(vlan_vid, site)) + else: + raise forms.ValidationError("Global VLAN {} not found".format(vlan_vid)) class PrefixBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm): @@ -589,6 +584,8 @@ class IPAddressCSVForm(forms.ModelForm): def clean(self): + super(IPAddressCSVForm, self).clean() + device = self.cleaned_data.get('device') interface_name = self.cleaned_data.get('interface_name') is_primary = self.cleaned_data.get('is_primary') @@ -596,17 +593,17 @@ class IPAddressCSVForm(forms.ModelForm): # Validate interface if device and interface_name: try: - Interface.objects.get(device=device, name=interface_name) + self.instance.interface = Interface.objects.get(device=device, name=interface_name) except Interface.DoesNotExist: - self.add_error('interface_name', "Invalid interface ({}) for {}".format(interface_name, device)) + raise forms.ValidationError("Invalid interface {} for device {}".format(interface_name, device)) elif device and not interface_name: - self.add_error('interface_name', "Device set ({}) but interface missing".format(device)) + raise forms.ValidationError("Device set ({}) but interface missing".format(device)) elif interface_name and not device: - self.add_error('device', "Interface set ({}) but device missing or invalid".format(interface_name)) + raise forms.ValidationError("Interface set ({}) but device missing or invalid".format(interface_name)) # Validate is_primary if is_primary and not device: - self.add_error('is_primary', "No device specified; cannot set as primary IP") + raise forms.ValidationError("No device specified; cannot set as primary IP") def save(self, *args, **kwargs): @@ -732,7 +729,7 @@ class VLANCSVForm(forms.ModelForm): } ) group_name = forms.CharField( - help_text='Name of parent VLAN group', + help_text='Name of VLAN group', required=False ) tenant = forms.ModelChoiceField( @@ -764,25 +761,20 @@ class VLANCSVForm(forms.ModelForm): def clean(self): - # Validate VLANGroup + super(VLANCSVForm, self).clean() + + site = self.cleaned_data.get('site') group_name = self.cleaned_data.get('group_name') + + # Validate VLAN group if group_name: try: - VLANGroup.objects.get(site=self.cleaned_data.get('site'), name=group_name) + self.instance.group = VLANGroup.objects.get(site=site, name=group_name) except VLANGroup.DoesNotExist: - self.add_error('group_name', "Invalid VLAN group {}.".format(group_name)) - - def save(self, *args, **kwargs): - - vlan = super(VLANCSVForm, self).save(commit=False) - - # Assign VLANGroup by site and name - if self.cleaned_data['group_name']: - vlan.group = VLANGroup.objects.get(site=self.cleaned_data['site'], name=self.cleaned_data['group_name']) - - if kwargs.get('commit'): - vlan.save() - return vlan + if site: + raise forms.ValidationError("VLAN group {} not found for site {}".format(group_name, site)) + else: + raise forms.ValidationError("Global VLAN group {} not found".format(group_name)) class VLANBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm): diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index 01cdd406d..04f193dd4 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -498,9 +498,7 @@ class VLANGroup(models.Model): verbose_name_plural = 'VLAN groups' def __str__(self): - if self.site is None: - return self.name - return '{} - {}'.format(self.site.name, self.name) + return self.name def get_absolute_url(self): return "{}?group_id={}".format(reverse('ipam:vlan_list'), self.pk) diff --git a/netbox/templates/utilities/obj_import.html b/netbox/templates/utilities/obj_import.html index 5ff55b399..22e06f6ef 100644 --- a/netbox/templates/utilities/obj_import.html +++ b/netbox/templates/utilities/obj_import.html @@ -29,7 +29,6 @@
- {% block instructions %}{% endblock %} {% if fields %}

CSV Format