mirror of
https://github.com/netbox-community/netbox.git
synced 2026-03-21 00:50:18 +01:00
Add choices ArrayField to CustomField; drop CustomFieldChoice
This commit is contained in:
@@ -7,7 +7,7 @@ from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.fields import CreateOnlyDefault
|
||||
|
||||
from extras.choices import *
|
||||
from extras.models import CustomField, CustomFieldChoice
|
||||
from extras.models import CustomField
|
||||
from utilities.api import ValidatedModelSerializer
|
||||
|
||||
|
||||
@@ -37,12 +37,6 @@ class CustomFieldDefaultValues:
|
||||
elif field.type == CustomFieldTypeChoices.TYPE_BOOLEAN:
|
||||
# TODO: Fix default value assignment for boolean custom fields
|
||||
field_value = False if field.default.lower() == 'false' else bool(field.default)
|
||||
elif field.type == CustomFieldTypeChoices.TYPE_SELECT:
|
||||
try:
|
||||
field_value = field.choices.get(value=field.default).pk
|
||||
except ObjectDoesNotExist:
|
||||
# Invalid default value
|
||||
field_value = None
|
||||
else:
|
||||
field_value = field.default
|
||||
value[field.name] = field_value
|
||||
@@ -69,9 +63,7 @@ class CustomFieldsSerializer(serializers.BaseSerializer):
|
||||
try:
|
||||
cf = custom_fields[field_name]
|
||||
except KeyError:
|
||||
raise ValidationError(
|
||||
"Invalid custom field for {} objects: {}".format(content_type, field_name)
|
||||
)
|
||||
raise ValidationError(f"Invalid custom field for {content_type} objects: {field_name}")
|
||||
|
||||
# Data validation
|
||||
if value not in [None, '']:
|
||||
@@ -81,15 +73,11 @@ class CustomFieldsSerializer(serializers.BaseSerializer):
|
||||
try:
|
||||
int(value)
|
||||
except ValueError:
|
||||
raise ValidationError(
|
||||
"Invalid value for integer field {}: {}".format(field_name, value)
|
||||
)
|
||||
raise ValidationError(f"Invalid value for integer field {field_name}: {value}")
|
||||
|
||||
# Validate boolean
|
||||
if cf.type == CustomFieldTypeChoices.TYPE_BOOLEAN and value not in [True, False, 1, 0]:
|
||||
raise ValidationError(
|
||||
"Invalid value for boolean field {}: {}".format(field_name, value)
|
||||
)
|
||||
raise ValidationError(f"Invalid value for boolean field {field_name}: {value}")
|
||||
|
||||
# Validate date
|
||||
if cf.type == CustomFieldTypeChoices.TYPE_DATE:
|
||||
@@ -97,25 +85,16 @@ class CustomFieldsSerializer(serializers.BaseSerializer):
|
||||
datetime.strptime(value, '%Y-%m-%d')
|
||||
except ValueError:
|
||||
raise ValidationError(
|
||||
"Invalid date for field {}: {}. (Required format is YYYY-MM-DD.)".format(field_name, value)
|
||||
f"Invalid date for field {field_name}: {value}. (Required format is YYYY-MM-DD.)"
|
||||
)
|
||||
|
||||
# Validate selected choice
|
||||
if cf.type == CustomFieldTypeChoices.TYPE_SELECT:
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
raise ValidationError(
|
||||
"{}: Choice selections must be passed as integers.".format(field_name)
|
||||
)
|
||||
valid_choices = [c.pk for c in cf.choices.all()]
|
||||
if value not in valid_choices:
|
||||
raise ValidationError(
|
||||
"Invalid choice for field {}: {}".format(field_name, value)
|
||||
)
|
||||
if value not in cf.choices:
|
||||
raise ValidationError(f"Invalid choice for field {field_name}: {value}")
|
||||
|
||||
elif cf.required:
|
||||
raise ValidationError("Required field {} cannot be empty.".format(field_name))
|
||||
raise ValidationError(f"Required field {field_name} cannot be empty.")
|
||||
|
||||
# Check for missing required fields
|
||||
missing_fields = []
|
||||
@@ -157,20 +136,4 @@ class CustomFieldModelSerializer(ValidatedModelSerializer):
|
||||
def _populate_custom_fields(self, instance, custom_fields):
|
||||
instance.custom_fields = {}
|
||||
for field in custom_fields:
|
||||
value = instance.cf.get(field.name)
|
||||
if field.type == CustomFieldTypeChoices.TYPE_SELECT and value is not None:
|
||||
instance.custom_fields[field.name] = CustomFieldChoiceSerializer(value).data
|
||||
else:
|
||||
instance.custom_fields[field.name] = value
|
||||
|
||||
|
||||
class CustomFieldChoiceSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Imitate utilities.api.ChoiceFieldSerializer
|
||||
"""
|
||||
value = serializers.IntegerField(source='pk')
|
||||
label = serializers.CharField(source='value')
|
||||
|
||||
class Meta:
|
||||
model = CustomFieldChoice
|
||||
fields = ['value', 'label']
|
||||
instance.custom_fields[field.name] = instance.cf.get(field.name)
|
||||
|
||||
@@ -5,9 +5,6 @@ from . import views
|
||||
router = OrderedDefaultRouter()
|
||||
router.APIRootView = views.ExtrasRootView
|
||||
|
||||
# Custom field choices
|
||||
router.register('_custom_field_choices', views.CustomFieldChoicesViewSet, basename='custom-field-choice')
|
||||
|
||||
# Export templates
|
||||
router.register('export-templates', views.ExportTemplateViewSet)
|
||||
|
||||
|
||||
@@ -14,9 +14,7 @@ from rq import Worker
|
||||
|
||||
from extras import filters
|
||||
from extras.choices import JobResultStatusChoices
|
||||
from extras.models import (
|
||||
ConfigContext, CustomFieldChoice, ExportTemplate, ImageAttachment, ObjectChange, JobResult, Tag,
|
||||
)
|
||||
from extras.models import ConfigContext, ExportTemplate, ImageAttachment, ObjectChange, JobResult, Tag
|
||||
from extras.reports import get_report, get_reports, run_report
|
||||
from extras.scripts import get_script, get_scripts, run_script
|
||||
from utilities.api import IsAuthenticatedOrLoginNotRequired, ModelViewSet
|
||||
@@ -34,36 +32,6 @@ class ExtrasRootView(APIRootView):
|
||||
return 'Extras'
|
||||
|
||||
|
||||
#
|
||||
# Custom field choices
|
||||
#
|
||||
|
||||
class CustomFieldChoicesViewSet(ViewSet):
|
||||
"""
|
||||
"""
|
||||
permission_classes = [IsAuthenticatedOrLoginNotRequired]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CustomFieldChoicesViewSet, self).__init__(*args, **kwargs)
|
||||
|
||||
self._fields = OrderedDict()
|
||||
|
||||
for cfc in CustomFieldChoice.objects.all():
|
||||
self._fields.setdefault(cfc.field.name, {})
|
||||
self._fields[cfc.field.name][cfc.value] = cfc.pk
|
||||
|
||||
def list(self, request):
|
||||
return Response(self._fields)
|
||||
|
||||
def retrieve(self, request, pk):
|
||||
if pk not in self._fields:
|
||||
raise Http404
|
||||
return Response(self._fields[pk])
|
||||
|
||||
def get_view_name(self):
|
||||
return "Custom Field choices"
|
||||
|
||||
|
||||
#
|
||||
# Custom fields
|
||||
#
|
||||
@@ -77,19 +45,11 @@ class CustomFieldModelViewSet(ModelViewSet):
|
||||
|
||||
# Gather all custom fields for the model
|
||||
content_type = ContentType.objects.get_for_model(self.queryset.model)
|
||||
custom_fields = content_type.custom_fields.prefetch_related('choices')
|
||||
|
||||
# Cache all relevant CustomFieldChoices. This saves us from having to do a lookup per select field per object.
|
||||
custom_field_choices = {}
|
||||
for field in custom_fields:
|
||||
for cfc in field.choices.all():
|
||||
custom_field_choices[cfc.id] = cfc.value
|
||||
custom_field_choices = custom_field_choices
|
||||
custom_fields = content_type.custom_fields.all()
|
||||
|
||||
context = super().get_serializer_context()
|
||||
context.update({
|
||||
'custom_fields': custom_fields,
|
||||
'custom_field_choices': custom_field_choices,
|
||||
})
|
||||
return context
|
||||
|
||||
|
||||
Reference in New Issue
Block a user