From cadba74b1f404d363296e842e92f370330f92ed1 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 1 Dec 2020 11:03:05 -0500 Subject: [PATCH] #5306: Introduce CSVContentTypeField for cable termination types --- netbox/dcim/forms.py | 13 ++++++------- netbox/dcim/tests/test_views.py | 6 +++--- netbox/utilities/forms/fields.py | 17 +++++++++++++++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 53558236e..a8ed76338 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -22,9 +22,10 @@ from tenancy.forms import TenancyFilterForm, TenancyForm from tenancy.models import Tenant, TenantGroup from utilities.forms import ( APISelect, add_blank_choice, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, - ColorSelect, CommentField, CSVChoiceField, CSVModelChoiceField, CSVModelForm, DynamicModelChoiceField, - DynamicModelMultipleChoiceField, ExpandableNameField, form_from_model, JSONField, NumericArrayField, SelectWithPK, - SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES, + ColorSelect, CommentField, CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVModelForm, + DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField, form_from_model, JSONField, + NumericArrayField, SelectWithPK, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField, + BOOLEAN_WITH_BLANK_CHOICES, ) from virtualization.models import Cluster, ClusterGroup from .choices import * @@ -3758,10 +3759,9 @@ class CableCSVForm(CSVModelForm): to_field_name='name', help_text='Side A device' ) - side_a_type = CSVModelChoiceField( + side_a_type = CSVContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=CABLE_TERMINATION_MODELS, - to_field_name='model', help_text='Side A type' ) side_a_name = forms.CharField( @@ -3774,10 +3774,9 @@ class CableCSVForm(CSVModelForm): to_field_name='name', help_text='Side B device' ) - side_b_type = CSVModelChoiceField( + side_b_type = CSVContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=CABLE_TERMINATION_MODELS, - to_field_name='model', help_text='Side B type' ) side_b_name = forms.CharField( diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 3d395410a..97a4f3705 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1668,9 +1668,9 @@ class CableTestCase( cls.csv_data = ( "side_a_device,side_a_type,side_a_name,side_b_device,side_b_type,side_b_name", - "Device 3,interface,Interface 1,Device 4,interface,Interface 1", - "Device 3,interface,Interface 2,Device 4,interface,Interface 2", - "Device 3,interface,Interface 3,Device 4,interface,Interface 3", + "Device 3,dcim.interface,Interface 1,Device 4,dcim.interface,Interface 1", + "Device 3,dcim.interface,Interface 2,Device 4,dcim.interface,Interface 2", + "Device 3,dcim.interface,Interface 3,Device 4,dcim.interface,Interface 3", ) cls.bulk_edit_data = { diff --git a/netbox/utilities/forms/fields.py b/netbox/utilities/forms/fields.py index d5b65ecc0..a9904c11a 100644 --- a/netbox/utilities/forms/fields.py +++ b/netbox/utilities/forms/fields.py @@ -6,12 +6,11 @@ from io import StringIO import django_filters from django import forms from django.forms.fields import JSONField as _JSONField, InvalidJSONInput -from django.core.exceptions import MultipleObjectsReturned +from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.db.models import Count from django.forms import BoundField from django.urls import reverse -from utilities.api import get_serializer_for_model from utilities.choices import unpack_grouped_choices from utilities.validators import EnhancedURLValidator from . import widgets @@ -21,6 +20,7 @@ from .utils import expand_alphanumeric_pattern, expand_ipaddress_pattern __all__ = ( 'CommentField', 'CSVChoiceField', + 'CSVContentTypeField', 'CSVDataField', 'CSVModelChoiceField', 'DynamicModelChoiceField', @@ -141,6 +141,19 @@ class CSVModelChoiceField(forms.ModelChoiceField): ) +class CSVContentTypeField(CSVModelChoiceField): + + def to_python(self, value): + try: + app_label, model = value.split('.') + except ValueError: + raise forms.ValidationError(f'Object type must be specified as "."') + try: + return self.queryset.get(app_label=app_label, model=model) + except ObjectDoesNotExist: + raise forms.ValidationError(f'Invalid object type') + + class ExpandableNameField(forms.CharField): """ A field which allows for numeric range expansion