mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Fixes #1197: Fixed status assignment during bulk import of devices, prefixes, IPs, and VLANs
This commit is contained in:
@ -674,7 +674,7 @@ class BaseDeviceFromCSVForm(forms.ModelForm):
|
|||||||
queryset=Platform.objects.all(), required=False, to_field_name='name',
|
queryset=Platform.objects.all(), required=False, to_field_name='name',
|
||||||
error_messages={'invalid_choice': 'Invalid platform.'}
|
error_messages={'invalid_choice': 'Invalid platform.'}
|
||||||
)
|
)
|
||||||
status_name = forms.ChoiceField(choices=[(s[1], s[0]) for s in STATUS_CHOICES])
|
status = forms.CharField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = []
|
fields = []
|
||||||
@ -692,8 +692,12 @@ class BaseDeviceFromCSVForm(forms.ModelForm):
|
|||||||
except DeviceType.DoesNotExist:
|
except DeviceType.DoesNotExist:
|
||||||
self.add_error('model_name', "Invalid device type ({} {})".format(manufacturer, model_name))
|
self.add_error('model_name', "Invalid device type ({} {})".format(manufacturer, model_name))
|
||||||
|
|
||||||
def clean_status_name(self):
|
def clean_status(self):
|
||||||
return dict(self.fields['status_name'].choices)[self.cleaned_data['status_name']]
|
status_choices = {s[1].lower(): s[0] for s in STATUS_CHOICES}
|
||||||
|
try:
|
||||||
|
return status_choices[self.cleaned_data['status'].lower()]
|
||||||
|
except KeyError:
|
||||||
|
raise ValidationError("Invalid status: {}".format(self.cleaned_data['status']))
|
||||||
|
|
||||||
|
|
||||||
class DeviceFromCSVForm(BaseDeviceFromCSVForm):
|
class DeviceFromCSVForm(BaseDeviceFromCSVForm):
|
||||||
@ -707,8 +711,8 @@ class DeviceFromCSVForm(BaseDeviceFromCSVForm):
|
|||||||
|
|
||||||
class Meta(BaseDeviceFromCSVForm.Meta):
|
class Meta(BaseDeviceFromCSVForm.Meta):
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'asset_tag',
|
'name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'asset_tag', 'status',
|
||||||
'status_name', 'site', 'rack_name', 'position', 'face',
|
'site', 'rack_name', 'position', 'face',
|
||||||
]
|
]
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
@ -751,8 +755,8 @@ class ChildDeviceFromCSVForm(BaseDeviceFromCSVForm):
|
|||||||
|
|
||||||
class Meta(BaseDeviceFromCSVForm.Meta):
|
class Meta(BaseDeviceFromCSVForm.Meta):
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'asset_tag',
|
'name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'asset_tag', 'status',
|
||||||
'status_name', 'parent', 'device_bay_name',
|
'parent', 'device_bay_name',
|
||||||
]
|
]
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
|
|
||||||
from dcim.models import Site, Rack, Device, Interface
|
from dcim.models import Site, Rack, Device, Interface
|
||||||
@ -195,14 +196,16 @@ class PrefixFromCSVForm(forms.ModelForm):
|
|||||||
error_messages={'invalid_choice': 'Site not found.'})
|
error_messages={'invalid_choice': 'Site not found.'})
|
||||||
vlan_group_name = forms.CharField(required=False)
|
vlan_group_name = forms.CharField(required=False)
|
||||||
vlan_vid = forms.IntegerField(required=False)
|
vlan_vid = forms.IntegerField(required=False)
|
||||||
status_name = forms.ChoiceField(choices=[(s[1], s[0]) for s in PREFIX_STATUS_CHOICES])
|
status = forms.CharField()
|
||||||
role = forms.ModelChoiceField(queryset=Role.objects.all(), required=False, to_field_name='name',
|
role = forms.ModelChoiceField(queryset=Role.objects.all(), required=False, to_field_name='name',
|
||||||
error_messages={'invalid_choice': 'Invalid role.'})
|
error_messages={'invalid_choice': 'Invalid role.'})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Prefix
|
model = Prefix
|
||||||
fields = ['prefix', 'vrf', 'tenant', 'site', 'vlan_group_name', 'vlan_vid', 'status_name', 'role', 'is_pool',
|
fields = [
|
||||||
'description']
|
'prefix', 'vrf', 'tenant', 'site', 'vlan_group_name', 'vlan_vid', 'status', 'role', 'is_pool',
|
||||||
|
'description',
|
||||||
|
]
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
|
||||||
@ -237,12 +240,12 @@ class PrefixFromCSVForm(forms.ModelForm):
|
|||||||
except VLAN.MultipleObjectsReturned:
|
except VLAN.MultipleObjectsReturned:
|
||||||
self.add_error('vlan_vid', "Multiple VLANs found ({} - VID {})".format(site, vlan_vid))
|
self.add_error('vlan_vid', "Multiple VLANs found ({} - VID {})".format(site, vlan_vid))
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def clean_status(self):
|
||||||
|
status_choices = {s[1].lower(): s[0] for s in PREFIX_STATUS_CHOICES}
|
||||||
# Assign Prefix status by name
|
try:
|
||||||
self.instance.status = dict(self.fields['status_name'].choices)[self.cleaned_data['status_name']]
|
return status_choices[self.cleaned_data['status'].lower()]
|
||||||
|
except KeyError:
|
||||||
return super(PrefixFromCSVForm, self).save(*args, **kwargs)
|
raise ValidationError("Invalid status: {}".format(self.cleaned_data['status']))
|
||||||
|
|
||||||
|
|
||||||
class PrefixImportForm(BootstrapMixin, BulkImportForm):
|
class PrefixImportForm(BootstrapMixin, BulkImportForm):
|
||||||
@ -491,7 +494,7 @@ class IPAddressFromCSVForm(forms.ModelForm):
|
|||||||
error_messages={'invalid_choice': 'VRF not found.'})
|
error_messages={'invalid_choice': 'VRF not found.'})
|
||||||
tenant = forms.ModelChoiceField(Tenant.objects.all(), to_field_name='name', required=False,
|
tenant = forms.ModelChoiceField(Tenant.objects.all(), to_field_name='name', required=False,
|
||||||
error_messages={'invalid_choice': 'Tenant not found.'})
|
error_messages={'invalid_choice': 'Tenant not found.'})
|
||||||
status_name = forms.ChoiceField(choices=[(s[1], s[0]) for s in IPADDRESS_STATUS_CHOICES])
|
status = forms.CharField()
|
||||||
device = forms.ModelChoiceField(queryset=Device.objects.all(), required=False, to_field_name='name',
|
device = forms.ModelChoiceField(queryset=Device.objects.all(), required=False, to_field_name='name',
|
||||||
error_messages={'invalid_choice': 'Device not found.'})
|
error_messages={'invalid_choice': 'Device not found.'})
|
||||||
interface_name = forms.CharField(required=False)
|
interface_name = forms.CharField(required=False)
|
||||||
@ -499,7 +502,7 @@ class IPAddressFromCSVForm(forms.ModelForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPAddress
|
model = IPAddress
|
||||||
fields = ['address', 'vrf', 'tenant', 'status_name', 'device', 'interface_name', 'is_primary', 'description']
|
fields = ['address', 'vrf', 'tenant', 'status', 'device', 'interface_name', 'is_primary', 'description']
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
|
||||||
@ -522,10 +525,14 @@ class IPAddressFromCSVForm(forms.ModelForm):
|
|||||||
if is_primary and not device:
|
if is_primary and not device:
|
||||||
self.add_error('is_primary', "No device specified; cannot set as primary IP")
|
self.add_error('is_primary', "No device specified; cannot set as primary IP")
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def clean_status(self):
|
||||||
|
status_choices = {s[1].lower(): s[0] for s in IPADDRESS_STATUS_CHOICES}
|
||||||
|
try:
|
||||||
|
return status_choices[self.cleaned_data['status'].lower()]
|
||||||
|
except KeyError:
|
||||||
|
raise ValidationError("Invalid status: {}".format(self.cleaned_data['status']))
|
||||||
|
|
||||||
# Assign status by name
|
def save(self, *args, **kwargs):
|
||||||
self.instance.status = dict(self.fields['status_name'].choices)[self.cleaned_data['status_name']]
|
|
||||||
|
|
||||||
# Set interface
|
# Set interface
|
||||||
if self.cleaned_data['device'] and self.cleaned_data['interface_name']:
|
if self.cleaned_data['device'] and self.cleaned_data['interface_name']:
|
||||||
@ -650,7 +657,7 @@ class VLANFromCSVForm(forms.ModelForm):
|
|||||||
Tenant.objects.all(), to_field_name='name', required=False,
|
Tenant.objects.all(), to_field_name='name', required=False,
|
||||||
error_messages={'invalid_choice': 'Tenant not found.'}
|
error_messages={'invalid_choice': 'Tenant not found.'}
|
||||||
)
|
)
|
||||||
status_name = forms.ChoiceField(choices=[(s[1], s[0]) for s in VLAN_STATUS_CHOICES])
|
status = forms.CharField()
|
||||||
role = forms.ModelChoiceField(
|
role = forms.ModelChoiceField(
|
||||||
queryset=Role.objects.all(), required=False, to_field_name='name',
|
queryset=Role.objects.all(), required=False, to_field_name='name',
|
||||||
error_messages={'invalid_choice': 'Invalid role.'}
|
error_messages={'invalid_choice': 'Invalid role.'}
|
||||||
@ -658,7 +665,7 @@ class VLANFromCSVForm(forms.ModelForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VLAN
|
model = VLAN
|
||||||
fields = ['site', 'group_name', 'vid', 'name', 'tenant', 'status_name', 'role', 'description']
|
fields = ['site', 'group_name', 'vid', 'name', 'tenant', 'status', 'role', 'description']
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
|
||||||
@ -672,6 +679,13 @@ class VLANFromCSVForm(forms.ModelForm):
|
|||||||
except VLANGroup.DoesNotExist:
|
except VLANGroup.DoesNotExist:
|
||||||
self.add_error('group_name', "Invalid VLAN group {}.".format(group_name))
|
self.add_error('group_name', "Invalid VLAN group {}.".format(group_name))
|
||||||
|
|
||||||
|
def clean_status(self):
|
||||||
|
status_choices = {s[1].lower(): s[0] for s in VLAN_STATUS_CHOICES}
|
||||||
|
try:
|
||||||
|
return status_choices[self.cleaned_data['status'].lower()]
|
||||||
|
except KeyError:
|
||||||
|
raise ValidationError("Invalid status: {}".format(self.cleaned_data['status']))
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
|
||||||
vlan = super(VLANFromCSVForm, self).save(commit=False)
|
vlan = super(VLANFromCSVForm, self).save(commit=False)
|
||||||
@ -680,9 +694,6 @@ class VLANFromCSVForm(forms.ModelForm):
|
|||||||
if self.cleaned_data['group_name']:
|
if self.cleaned_data['group_name']:
|
||||||
vlan.group = VLANGroup.objects.get(site=self.cleaned_data['site'], name=self.cleaned_data['group_name'])
|
vlan.group = VLANGroup.objects.get(site=self.cleaned_data['site'], name=self.cleaned_data['group_name'])
|
||||||
|
|
||||||
# Assign VLAN status by name
|
|
||||||
vlan.status = dict(self.fields['status_name'].choices)[self.cleaned_data['status_name']]
|
|
||||||
|
|
||||||
if kwargs.get('commit'):
|
if kwargs.get('commit'):
|
||||||
vlan.save()
|
vlan.save()
|
||||||
return vlan
|
return vlan
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Site</td>
|
<td>Site</td>
|
||||||
<td>Name of assigned site</td>
|
<td>Name of assigned site (optional)</td>
|
||||||
<td>LAS2</td>
|
<td>LAS2</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
Reference in New Issue
Block a user