From 849db8fe449866419631b925ad005759a8453624 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 1 Nov 2018 09:59:53 -0400 Subject: [PATCH] Finished CableCSVForm --- netbox/dcim/forms.py | 35 +++++++++++++++----- netbox/utilities/forms.py | 41 ++++++++++++++++++++++-- netbox/utilities/templatetags/helpers.py | 11 +++++-- 3 files changed, 74 insertions(+), 13 deletions(-) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 78d7973b2..1e68069aa 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -1764,7 +1764,7 @@ class CableCSVForm(forms.ModelForm): side_a_device = FlexibleModelChoiceField( queryset=Device.objects.all(), to_field_name='name', - help_text='Console server name or ID', + help_text='Side A device name or ID', error_messages={ 'invalid_choice': 'Side A device not found', } @@ -1772,15 +1772,18 @@ class CableCSVForm(forms.ModelForm): side_a_type = forms.ModelChoiceField( queryset=ContentType.objects.all(), limit_choices_to={'model__in': CABLE_TERMINATION_TYPES}, - to_field_name='model' + to_field_name='model', + help_text='Side A type' + ) + side_a_name = forms.CharField( + help_text='Side A component' ) - side_a_name = forms.CharField() # Termination B side_b_device = FlexibleModelChoiceField( queryset=Device.objects.all(), to_field_name='name', - help_text='Console server name or ID', + help_text='Side B device name or ID', error_messages={ 'invalid_choice': 'Side B device not found', } @@ -1788,9 +1791,12 @@ class CableCSVForm(forms.ModelForm): side_b_type = forms.ModelChoiceField( queryset=ContentType.objects.all(), limit_choices_to={'model__in': CABLE_TERMINATION_TYPES}, - to_field_name='model' + to_field_name='model', + help_text='Side B type' + ) + side_b_name = forms.CharField( + help_text='Side B component' ) - side_b_name = forms.CharField() # Cable attributes status = CSVChoiceField( @@ -1798,13 +1804,26 @@ class CableCSVForm(forms.ModelForm): required=False, help_text='Connection status' ) + type = CSVChoiceField( + choices=CABLE_TYPE_CHOICES, + required=False, + help_text='Cable type' + ) + length_unit = CSVChoiceField( + choices=LENGTH_UNIT_CHOICES, + required=False, + help_text='Length unit' + ) class Meta: model = Cable fields = [ - 'side_a_device', 'side_a_type', 'side_a_name', 'side_b_device', 'side_b_type', 'side_b_name', 'status', - 'label', + 'side_a_device', 'side_a_type', 'side_a_name', 'side_b_device', 'side_b_type', 'side_b_name', 'type', + 'status', 'label', 'color', 'length', 'length_unit', ] + help_texts = { + 'color': 'RGB color in hexadecimal (e.g. 00ff00)' + } # TODO: Merge the clean() methods for either end def clean_side_a_name(self): diff --git a/netbox/utilities/forms.py b/netbox/utilities/forms.py index 57e89ac1d..b9b04a337 100644 --- a/netbox/utilities/forms.py +++ b/netbox/utilities/forms.py @@ -149,6 +149,43 @@ def add_blank_choice(choices): return ((None, '---------'),) + tuple(choices) +def unpack_grouped_choices(choices): + """ + Unpack a grouped choices hierarchy into a flat list of two-tuples. For example: + + choices = ( + ('Foo', ( + (1, 'A'), + (2, 'B') + )), + ('Bar', ( + (3, 'C'), + (4, 'D') + )) + ) + + becomes: + + choices = ( + (1, 'A'), + (2, 'B'), + (3, 'C'), + (4, 'D') + ) + """ + unpacked_choices = [] + for key, value in choices: + if key == 1300: + breakme = True + if isinstance(value, (list, tuple)): + # Entered an optgroup + for optgroup_key, optgroup_value in value: + unpacked_choices.append((optgroup_key, optgroup_value)) + else: + unpacked_choices.append((key, value)) + return unpacked_choices + + def utf8_encoder(data): for line in data: yield line.encode('utf-8') @@ -353,8 +390,8 @@ class CSVChoiceField(forms.ChoiceField): def __init__(self, choices, *args, **kwargs): super(CSVChoiceField, self).__init__(choices=choices, *args, **kwargs) - self.choices = [(label, label) for value, label in choices] - self.choice_values = {label: value for value, label in choices} + self.choices = [(label, label) for value, label in unpack_grouped_choices(choices)] + self.choice_values = {label: value for value, label in unpack_grouped_choices(choices)} def clean(self, value): value = super(CSVChoiceField, self).clean(value) diff --git a/netbox/utilities/templatetags/helpers.py b/netbox/utilities/templatetags/helpers.py index 555cbe03f..0d5063ae0 100644 --- a/netbox/utilities/templatetags/helpers.py +++ b/netbox/utilities/templatetags/helpers.py @@ -5,6 +5,9 @@ from django import template from django.utils.safestring import mark_safe from markdown import markdown +from utilities.forms import unpack_grouped_choices + + register = template.Library() @@ -113,14 +116,16 @@ def example_choices(field, arg=3): """ examples = [] if hasattr(field, 'queryset'): - choices = [(obj.pk, getattr(obj, field.to_field_name)) for obj in field.queryset[:arg + 1]] + choices = [ + (obj.pk, getattr(obj, field.to_field_name)) for obj in field.queryset[:arg + 1] + ] else: choices = field.choices - for id, label in choices: + for value, label in unpack_grouped_choices(choices): if len(examples) == arg: examples.append('etc.') break - if not id or not label: + if not value or not label: continue examples.append(label) return ', '.join(examples) or 'None'