1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Replaced all CSVForm ChoiceFields with CSVChoiceField

This commit is contained in:
Jeremy Stretch
2017-06-07 13:22:06 -04:00
parent 3924063060
commit e6c4ce51f7
7 changed files with 66 additions and 91 deletions

View File

@ -14,7 +14,7 @@ from tenancy.forms import TenancyForm
from tenancy.models import Tenant
from utilities.forms import (
APISelect, add_blank_choice, ArrayFieldSelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
ChainedFieldsMixin, ChainedModelChoiceField, CommentField, ExpandableNameField, FilterChoiceField,
ChainedFieldsMixin, ChainedModelChoiceField, CommentField, CSVChoiceField, ExpandableNameField, FilterChoiceField,
FlexibleModelChoiceField, Livesearch, SelectWithDisabled, SmallTextarea, SlugField,
FilterTreeNodeMultipleChoiceField,
)
@ -24,8 +24,9 @@ from .models import (
ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceRole, DeviceType,
Interface, IFACE_FF_CHOICES, IFACE_FF_LAG, IFACE_ORDERING_CHOICES, InterfaceConnection, InterfaceTemplate,
Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate,
RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, Rack, RackGroup, RackReservation, RackRole, Region, Site, STATUS_CHOICES,
SUBDEVICE_ROLE_CHILD, SUBDEVICE_ROLE_PARENT, VIRTUAL_IFACE_TYPES,
RACK_FACE_CHOICES, RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, Rack, RackGroup, RackReservation, RackRole,
RACK_WIDTH_19IN, RACK_WIDTH_23IN, Region, Site, STATUS_CHOICES, SUBDEVICE_ROLE_CHILD, SUBDEVICE_ROLE_PARENT,
VIRTUAL_IFACE_TYPES,
)
@ -50,31 +51,6 @@ def get_device_by_name_or_pk(name):
return device
class ConnectionStatusCSVField(forms.ChoiceField):
"""
This field accepts either "planned" or "connected" as a connection status for CSV imports.
"""
default_error_messages = {
'invalid_choice': '%(value)s is not a valid connection status. It must be either "planned" or "connected."',
}
def __init__(self, *args, **kwargs):
kwargs['choices'] = (
('planned', 'planned'),
('connected', 'connected'),
)
super(ConnectionStatusCSVField, self).__init__(*args, **kwargs)
if not self.help_text:
self.help_text = 'Connection status'
def clean(self, value):
value = super(ConnectionStatusCSVField, self).clean(value)
return {
'planned': CONNECTION_STATUS_PLANNED,
'connected': CONNECTION_STATUS_CONNECTED,
}[value.lower()]
class DeviceComponentForm(BootstrapMixin, forms.Form):
"""
Allow inclusion of the parent device as context for limiting field choices.
@ -256,7 +232,7 @@ class RackCSVForm(forms.ModelForm):
queryset=RackGroup.objects.all(),
to_field_name='name',
required=False,
help_text='Name of parent group',
help_text='Name of parent rack group',
error_messages={
'invalid_choice': 'Rack group not found.',
}
@ -279,15 +255,24 @@ class RackCSVForm(forms.ModelForm):
'invalid_choice': 'Role not found.',
}
)
type = CSVChoiceField(
choices=RACK_TYPE_CHOICES,
required=False,
help_text='Rack type'
)
width = forms.ChoiceField(
choices = (
(RACK_WIDTH_19IN, '19'),
(RACK_WIDTH_23IN, '23'),
),
help_text='Rail-to-rail width (in inches)'
)
class Meta:
model = Rack
fields = [
'site', 'group', 'name', 'facility_id', 'tenant', 'role', 'type', 'width', 'u_height', 'desc_units',
]
help_texts = {
'type': 'Rack type',
}
def clean_group(self):
@ -297,21 +282,6 @@ class RackCSVForm(forms.ModelForm):
if group and group.site != site:
raise ValidationError("Invalid group for site {}: {}".format(site, group))
def clean_type(self):
rack_type = self.cleaned_data['type']
if not rack_type:
return None
try:
choices = {v.lower(): k for k, v in RACK_TYPE_CHOICES}
return choices[rack_type.lower()]
except KeyError:
raise forms.ValidationError('Invalid rack type ({}). Valid choices are: {}.'.format(
rack_type,
', '.join({v: k for k, v in RACK_TYPE_CHOICES}),
))
class RackBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
pk = forms.ModelMultipleChoiceField(queryset=Rack.objects.all(), widget=forms.MultipleHiddenInput)
@ -752,8 +722,9 @@ class BaseDeviceCSVForm(forms.ModelForm):
'invalid_choice': 'Invalid platform.',
}
)
status = forms.CharField(
help_text='Status name'
status = CSVChoiceField(
choices=STATUS_CHOICES,
help_text='Operational status of device'
)
class Meta:
@ -772,13 +743,6 @@ class BaseDeviceCSVForm(forms.ModelForm):
except DeviceType.DoesNotExist:
self.add_error('model_name', "Invalid device type ({} {})".format(manufacturer, model_name))
def clean_status(self):
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 DeviceCSVForm(BaseDeviceCSVForm):
site = forms.ModelChoiceField(
@ -793,9 +757,10 @@ class DeviceCSVForm(BaseDeviceCSVForm):
required=False,
help_text='Name of parent rack'
)
face = forms.CharField(
face = CSVChoiceField(
choices=RACK_FACE_CHOICES,
required=False,
help_text='Mounted rack face (front or rear)'
help_text='Mounted rack face'
)
class Meta(BaseDeviceCSVForm.Meta):
@ -991,7 +956,10 @@ class ConsoleConnectionCSVForm(forms.ModelForm):
console_port = forms.CharField(
help_text='Console port name'
)
connection_status = ConnectionStatusCSVField()
connection_status = CSVChoiceField(
choices=CONNECTION_STATUS_CHOICES,
help_text='Connection status'
)
class Meta:
model = ConsolePort
@ -1245,7 +1213,10 @@ class PowerConnectionCSVForm(forms.ModelForm):
power_port = forms.CharField(
help_text='Power port name'
)
connection_status = ConnectionStatusCSVField()
connection_status = CSVChoiceField(
choices=CONNECTION_STATUS_CHOICES,
help_text='Connection status'
)
class Meta:
model = PowerPort
@ -1645,7 +1616,10 @@ class InterfaceConnectionCSVForm(forms.ModelForm):
interface_b = forms.CharField(
help_text='Interface name'
)
connection_status = ConnectionStatusCSVField()
connection_status = CSVChoiceField(
choices=CONNECTION_STATUS_CHOICES,
help_text='Connection status'
)
class Meta:
model = InterfaceConnection

View File

@ -346,7 +346,7 @@ class RackGroup(models.Model):
]
def __str__(self):
return '{} - {}'.format(self.site.name, self.name)
return self.name
def get_absolute_url(self):
return "{}?group_id={}".format(reverse('dcim:rack_list'), self.pk)

View File

@ -247,7 +247,7 @@ class RackImportTable(BaseTable):
class Meta(BaseTable.Meta):
model = Rack
fields = ('site', 'group', 'name', 'facility_id', 'tenant', 'u_height')
fields = ('name', 'site', 'group', 'facility_id', 'tenant', 'u_height')
#

View File

@ -9,8 +9,8 @@ from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFi
from tenancy.forms import TenancyForm
from tenancy.models import Tenant
from utilities.forms import (
APISelect, BootstrapMixin, BulkEditNullBooleanSelect, ChainedModelChoiceField, ExpandableIPAddressField,
FilterChoiceField, Livesearch, ReturnURLForm, SlugField, add_blank_choice,
APISelect, BootstrapMixin, BulkEditNullBooleanSelect, ChainedModelChoiceField, CSVChoiceField,
ExpandableIPAddressField, FilterChoiceField, Livesearch, ReturnURLForm, SlugField, add_blank_choice,
)
from .models import (
Aggregate, IPAddress, IPADDRESS_STATUS_CHOICES, Prefix, PREFIX_STATUS_CHOICES, RIR, Role, Service, VLAN,
@ -238,7 +238,8 @@ class PrefixCSVForm(forms.ModelForm):
help_text='Numeric ID of assigned VLAN',
required=False
)
status = forms.CharField(
status = CSVChoiceField(
choices=IPADDRESS_STATUS_CHOICES,
help_text='Status name'
)
role = forms.ModelChoiceField(
@ -289,13 +290,6 @@ class PrefixCSVForm(forms.ModelForm):
except VLAN.MultipleObjectsReturned:
self.add_error('vlan_vid', "Multiple VLANs found ({} - VID {})".format(site, vlan_vid))
def clean_status(self):
status_choices = {s[1].lower(): s[0] for s in PREFIX_STATUS_CHOICES}
try:
return status_choices[self.cleaned_data['status'].lower()]
except KeyError:
raise ValidationError("Invalid status: {}".format(self.cleaned_data['status']))
class PrefixBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
pk = forms.ModelMultipleChoiceField(queryset=Prefix.objects.all(), widget=forms.MultipleHiddenInput)
@ -567,7 +561,8 @@ class IPAddressCSVForm(forms.ModelForm):
'invalid_choice': 'Tenant not found.',
}
)
status = forms.CharField(
status = CSVChoiceField(
choices=PREFIX_STATUS_CHOICES,
help_text='Status name'
)
device = forms.ModelChoiceField(
@ -613,13 +608,6 @@ class IPAddressCSVForm(forms.ModelForm):
if is_primary and not device:
self.add_error('is_primary', "No device specified; cannot set as primary IP")
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']))
def save(self, *args, **kwargs):
# Set interface
@ -756,7 +744,8 @@ class VLANCSVForm(forms.ModelForm):
'invalid_choice': 'Tenant not found.',
}
)
status = forms.CharField(
status = CSVChoiceField(
choices=VLAN_STATUS_CHOICES,
help_text='Status name'
)
role = forms.ModelChoiceField(
@ -783,13 +772,6 @@ class VLANCSVForm(forms.ModelForm):
except VLANGroup.DoesNotExist:
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):
vlan = super(VLANCSVForm, self).save(commit=False)

View File

@ -45,7 +45,7 @@
<td>
{{ field.help_text|default:field.label }}
{% if field.choices %}
<br /><small class="text-muted">Examples: {{ field.choices|example_choices }}</small>
<br /><small class="text-muted">Choices: {{ field.choices|example_choices }}</small>
{% elif field|widget_type == 'dateinput' %}
<br /><small class="text-muted">Format: YYYY-MM-DD</small>
{% elif field|widget_type == 'checkboxinput' %}

View File

@ -271,6 +271,25 @@ class CSVDataField(forms.CharField):
return records
class CSVChoiceField(forms.ChoiceField):
"""
Invert the provided set of choices to take the human-friendly label as input, and return the database value.
"""
def __init__(self, choices, *args, **kwargs):
super(CSVChoiceField, self).__init__(choices, *args, **kwargs)
self.choices = [(label, label) for value, label in choices]
self.choice_values = {label: value for value, label in choices}
def clean(self, value):
value = super(CSVChoiceField, self).clean(value)
if not value:
return None
if value not in self.choice_values:
raise forms.ValidationError("Invalid choice: {}".format(value))
return self.choice_values[value]
class ExpandableNameField(forms.CharField):
"""
A field which allows for numeric range expansion

View File

@ -75,7 +75,7 @@ def example_choices(value, arg=3):
if not id:
continue
choices.append(label)
return ', '.join(choices) or 'None found'
return ', '.join(choices) or 'None'
#