Closes #8307: Add data_type indicator to REST API serializer for custom fields

This commit is contained in:
jeremystretch 2022-01-18 16:57:54 -05:00
parent 3e3880823b
commit 3fcae36cf1
3 changed files with 93 additions and 22 deletions

View File

@ -71,6 +71,7 @@ Inventory item templates can be arranged hierarchically within a device type, an
* [#8168](https://github.com/netbox-community/netbox/issues/8168) - Add `min_vid` and `max_vid` fields to VLAN group
* [#8295](https://github.com/netbox-community/netbox/issues/8295) - Webhook URLs can now be templatized
* [#8296](https://github.com/netbox-community/netbox/issues/8296) - Allow disabling custom links
* [#8307](https://github.com/netbox-community/netbox/issues/8307) - Add `data_type` indicator to REST API serializer for custom fields
### Other Changes

View File

@ -79,15 +79,28 @@ class CustomFieldSerializer(ValidatedModelSerializer):
)
type = ChoiceField(choices=CustomFieldTypeChoices)
filter_logic = ChoiceField(choices=CustomFieldFilterLogicChoices, required=False)
data_type = serializers.SerializerMethodField()
class Meta:
model = CustomField
fields = [
'id', 'url', 'display', 'content_types', 'type', 'name', 'label', 'description', 'required', 'filter_logic',
'default', 'weight', 'validation_minimum', 'validation_maximum', 'validation_regex', 'choices', 'created',
'last_updated',
'id', 'url', 'display', 'content_types', 'type', 'data_type', 'name', 'label', 'description', 'required',
'filter_logic', 'default', 'weight', 'validation_minimum', 'validation_maximum', 'validation_regex',
'choices', 'created', 'last_updated',
]
def get_data_type(self, obj):
types = CustomFieldTypeChoices
if obj.type == types.TYPE_INTEGER:
return 'integer'
if obj.type == types.TYPE_BOOLEAN:
return 'boolean'
if obj.type in (types.TYPE_JSON, types.TYPE_OBJECT):
return 'object'
if obj.type in (types.TYPE_MULTISELECT, types.TYPE_MULTIOBJECT):
return 'array'
return 'string'
#
# Custom links

View File

@ -378,9 +378,22 @@ class CustomFieldAPITest(APITestCase):
CustomField(type=CustomFieldTypeChoices.TYPE_DATE, name='date_field', default='2020-01-01'),
CustomField(type=CustomFieldTypeChoices.TYPE_URL, name='url_field', default='http://example.com/1'),
CustomField(type=CustomFieldTypeChoices.TYPE_JSON, name='json_field', default='{"x": "y"}'),
CustomField(type=CustomFieldTypeChoices.TYPE_SELECT, name='choice_field', default='Foo', choices=(
'Foo', 'Bar', 'Baz'
)),
CustomField(
type=CustomFieldTypeChoices.TYPE_SELECT,
name='select_field',
default='Foo',
choices=(
'Foo', 'Bar', 'Baz'
)
),
CustomField(
type=CustomFieldTypeChoices.TYPE_MULTISELECT,
name='multiselect_field',
default=['Foo'],
choices=(
'Foo', 'Bar', 'Baz'
)
),
CustomField(
type=CustomFieldTypeChoices.TYPE_OBJECT,
name='object_field',
@ -416,11 +429,37 @@ class CustomFieldAPITest(APITestCase):
custom_fields[5].name: 'http://example.com/2',
custom_fields[6].name: '{"foo": 1, "bar": 2}',
custom_fields[7].name: 'Bar',
custom_fields[8].name: vlans[1].pk,
custom_fields[9].name: [vlans[2].pk, vlans[3].pk],
custom_fields[8].name: ['Bar', 'Baz'],
custom_fields[9].name: vlans[1].pk,
custom_fields[10].name: [vlans[2].pk, vlans[3].pk],
}
sites[1].save()
def test_get_custom_fields(self):
TYPES = {
CustomFieldTypeChoices.TYPE_TEXT: 'string',
CustomFieldTypeChoices.TYPE_LONGTEXT: 'string',
CustomFieldTypeChoices.TYPE_INTEGER: 'integer',
CustomFieldTypeChoices.TYPE_BOOLEAN: 'boolean',
CustomFieldTypeChoices.TYPE_DATE: 'string',
CustomFieldTypeChoices.TYPE_URL: 'string',
CustomFieldTypeChoices.TYPE_JSON: 'object',
CustomFieldTypeChoices.TYPE_SELECT: 'string',
CustomFieldTypeChoices.TYPE_MULTISELECT: 'array',
CustomFieldTypeChoices.TYPE_OBJECT: 'object',
CustomFieldTypeChoices.TYPE_MULTIOBJECT: 'array',
}
self.add_permissions('extras.view_customfield')
url = reverse('extras-api:customfield-list')
response = self.client.get(url, **self.header)
self.assertEqual(response.data['count'], len(TYPES))
# Validate data types
for customfield in response.data['results']:
cf_type = customfield['type']['value']
self.assertEqual(customfield['data_type'], TYPES[cf_type])
def test_get_single_object_without_custom_field_data(self):
"""
Validate that custom fields are present on an object even if it has no values defined.
@ -439,7 +478,8 @@ class CustomFieldAPITest(APITestCase):
'date_field': None,
'url_field': None,
'json_field': None,
'choice_field': None,
'select_field': None,
'multiselect_field': None,
'object_field': None,
'multiobject_field': None,
})
@ -462,7 +502,8 @@ class CustomFieldAPITest(APITestCase):
self.assertEqual(response.data['custom_fields']['date_field'], site2_cfvs['date_field'])
self.assertEqual(response.data['custom_fields']['url_field'], site2_cfvs['url_field'])
self.assertEqual(response.data['custom_fields']['json_field'], site2_cfvs['json_field'])
self.assertEqual(response.data['custom_fields']['choice_field'], site2_cfvs['choice_field'])
self.assertEqual(response.data['custom_fields']['select_field'], site2_cfvs['select_field'])
self.assertEqual(response.data['custom_fields']['multiselect_field'], site2_cfvs['multiselect_field'])
self.assertEqual(response.data['custom_fields']['object_field']['id'], site2_cfvs['object_field'])
self.assertEqual(
[obj['id'] for obj in response.data['custom_fields']['multiobject_field']],
@ -495,7 +536,8 @@ class CustomFieldAPITest(APITestCase):
self.assertEqual(response_cf['date_field'], cf_defaults['date_field'])
self.assertEqual(response_cf['url_field'], cf_defaults['url_field'])
self.assertEqual(response_cf['json_field'], cf_defaults['json_field'])
self.assertEqual(response_cf['choice_field'], cf_defaults['choice_field'])
self.assertEqual(response_cf['select_field'], cf_defaults['select_field'])
self.assertEqual(response_cf['multiselect_field'], cf_defaults['multiselect_field'])
self.assertEqual(response_cf['object_field']['id'], cf_defaults['object_field'])
self.assertEqual(
[obj['id'] for obj in response.data['custom_fields']['multiobject_field']],
@ -511,7 +553,8 @@ class CustomFieldAPITest(APITestCase):
self.assertEqual(str(site.custom_field_data['date_field']), cf_defaults['date_field'])
self.assertEqual(site.custom_field_data['url_field'], cf_defaults['url_field'])
self.assertEqual(site.custom_field_data['json_field'], cf_defaults['json_field'])
self.assertEqual(site.custom_field_data['choice_field'], cf_defaults['choice_field'])
self.assertEqual(site.custom_field_data['select_field'], cf_defaults['select_field'])
self.assertEqual(site.custom_field_data['multiselect_field'], cf_defaults['multiselect_field'])
self.assertEqual(site.custom_field_data['object_field'], cf_defaults['object_field'])
self.assertEqual(site.custom_field_data['multiobject_field'], cf_defaults['multiobject_field'])
@ -530,7 +573,8 @@ class CustomFieldAPITest(APITestCase):
'date_field': '2020-01-02',
'url_field': 'http://example.com/2',
'json_field': '{"foo": 1, "bar": 2}',
'choice_field': 'Bar',
'select_field': 'Bar',
'multiselect_field': ['Bar', 'Baz'],
'object_field': VLAN.objects.get(vid=2).pk,
'multiobject_field': list(VLAN.objects.filter(vid__in=[3, 4]).values_list('pk', flat=True)),
},
@ -551,7 +595,8 @@ class CustomFieldAPITest(APITestCase):
self.assertEqual(response_cf['date_field'], data_cf['date_field'])
self.assertEqual(response_cf['url_field'], data_cf['url_field'])
self.assertEqual(response_cf['json_field'], data_cf['json_field'])
self.assertEqual(response_cf['choice_field'], data_cf['choice_field'])
self.assertEqual(response_cf['select_field'], data_cf['select_field'])
self.assertEqual(response_cf['multiselect_field'], data_cf['multiselect_field'])
self.assertEqual(response_cf['object_field']['id'], data_cf['object_field'])
self.assertEqual(
[obj['id'] for obj in response_cf['multiobject_field']],
@ -567,7 +612,8 @@ class CustomFieldAPITest(APITestCase):
self.assertEqual(str(site.custom_field_data['date_field']), data_cf['date_field'])
self.assertEqual(site.custom_field_data['url_field'], data_cf['url_field'])
self.assertEqual(site.custom_field_data['json_field'], data_cf['json_field'])
self.assertEqual(site.custom_field_data['choice_field'], data_cf['choice_field'])
self.assertEqual(site.custom_field_data['select_field'], data_cf['select_field'])
self.assertEqual(site.custom_field_data['multiselect_field'], data_cf['multiselect_field'])
self.assertEqual(site.custom_field_data['object_field'], data_cf['object_field'])
self.assertEqual(site.custom_field_data['multiobject_field'], data_cf['multiobject_field'])
@ -611,7 +657,8 @@ class CustomFieldAPITest(APITestCase):
self.assertEqual(response_cf['date_field'], cf_defaults['date_field'])
self.assertEqual(response_cf['url_field'], cf_defaults['url_field'])
self.assertEqual(response_cf['json_field'], cf_defaults['json_field'])
self.assertEqual(response_cf['choice_field'], cf_defaults['choice_field'])
self.assertEqual(response_cf['select_field'], cf_defaults['select_field'])
self.assertEqual(response_cf['multiselect_field'], cf_defaults['multiselect_field'])
self.assertEqual(response_cf['object_field']['id'], cf_defaults['object_field'])
self.assertEqual(
[obj['id'] for obj in response_cf['multiobject_field']],
@ -627,7 +674,8 @@ class CustomFieldAPITest(APITestCase):
self.assertEqual(str(site.custom_field_data['date_field']), cf_defaults['date_field'])
self.assertEqual(site.custom_field_data['url_field'], cf_defaults['url_field'])
self.assertEqual(site.custom_field_data['json_field'], cf_defaults['json_field'])
self.assertEqual(site.custom_field_data['choice_field'], cf_defaults['choice_field'])
self.assertEqual(site.custom_field_data['select_field'], cf_defaults['select_field'])
self.assertEqual(site.custom_field_data['multiselect_field'], cf_defaults['multiselect_field'])
self.assertEqual(site.custom_field_data['object_field'], cf_defaults['object_field'])
self.assertEqual(site.custom_field_data['multiobject_field'], cf_defaults['multiobject_field'])
@ -643,7 +691,8 @@ class CustomFieldAPITest(APITestCase):
'date_field': '2020-01-02',
'url_field': 'http://example.com/2',
'json_field': '{"foo": 1, "bar": 2}',
'choice_field': 'Bar',
'select_field': 'Bar',
'multiselect_field': ['Bar', 'Baz'],
'object_field': VLAN.objects.get(vid=2).pk,
'multiobject_field': list(VLAN.objects.filter(vid__in=[3, 4]).values_list('pk', flat=True)),
}
@ -682,7 +731,9 @@ class CustomFieldAPITest(APITestCase):
self.assertEqual(response_cf['date_field'], custom_field_data['date_field'])
self.assertEqual(response_cf['url_field'], custom_field_data['url_field'])
self.assertEqual(response_cf['json_field'], custom_field_data['json_field'])
self.assertEqual(response_cf['choice_field'], custom_field_data['choice_field'])
self.assertEqual(response_cf['select_field'], custom_field_data['select_field'])
self.assertEqual(response_cf['multiselect_field'], custom_field_data['multiselect_field'])
self.assertEqual(response_cf['object_field']['id'], custom_field_data['object_field'])
self.assertEqual(
[obj['id'] for obj in response_cf['multiobject_field']],
custom_field_data['multiobject_field']
@ -697,7 +748,9 @@ class CustomFieldAPITest(APITestCase):
self.assertEqual(str(site.custom_field_data['date_field']), custom_field_data['date_field'])
self.assertEqual(site.custom_field_data['url_field'], custom_field_data['url_field'])
self.assertEqual(site.custom_field_data['json_field'], custom_field_data['json_field'])
self.assertEqual(site.custom_field_data['choice_field'], custom_field_data['choice_field'])
self.assertEqual(site.custom_field_data['select_field'], custom_field_data['select_field'])
self.assertEqual(site.custom_field_data['multiselect_field'], custom_field_data['multiselect_field'])
self.assertEqual(site.custom_field_data['object_field'], custom_field_data['object_field'])
self.assertEqual(site.custom_field_data['multiobject_field'], custom_field_data['multiobject_field'])
def test_update_single_object_with_values(self):
@ -728,7 +781,9 @@ class CustomFieldAPITest(APITestCase):
self.assertEqual(response_cf['date_field'], original_cfvs['date_field'])
self.assertEqual(response_cf['url_field'], original_cfvs['url_field'])
self.assertEqual(response_cf['json_field'], original_cfvs['json_field'])
self.assertEqual(response_cf['choice_field'], original_cfvs['choice_field'])
self.assertEqual(response_cf['select_field'], original_cfvs['select_field'])
self.assertEqual(response_cf['multiselect_field'], original_cfvs['multiselect_field'])
self.assertEqual(response_cf['object_field']['id'], original_cfvs['object_field'])
self.assertEqual(
[obj['id'] for obj in response_cf['multiobject_field']],
original_cfvs['multiobject_field']
@ -743,7 +798,9 @@ class CustomFieldAPITest(APITestCase):
self.assertEqual(site2.custom_field_data['date_field'], original_cfvs['date_field'])
self.assertEqual(site2.custom_field_data['url_field'], original_cfvs['url_field'])
self.assertEqual(site2.custom_field_data['json_field'], original_cfvs['json_field'])
self.assertEqual(site2.custom_field_data['choice_field'], original_cfvs['choice_field'])
self.assertEqual(site2.custom_field_data['select_field'], original_cfvs['select_field'])
self.assertEqual(site2.custom_field_data['multiselect_field'], original_cfvs['multiselect_field'])
self.assertEqual(site2.custom_field_data['object_field'], original_cfvs['object_field'])
self.assertEqual(site2.custom_field_data['multiobject_field'], original_cfvs['multiobject_field'])
def test_minimum_maximum_values_validation(self):