Fixes #1226: Improve validation for custom field values submitted via the API

This commit is contained in:
Jeremy Stretch 2017-05-31 14:09:57 -04:00
parent f03a378ce0
commit 293dbd8a8b
2 changed files with 26 additions and 5 deletions

View File

@ -1,4 +1,5 @@
from __future__ import unicode_literals
from datetime import datetime
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
@ -6,7 +7,9 @@ from rest_framework.exceptions import ValidationError
from django.contrib.contenttypes.models import ContentType
from django.db import transaction
from extras.models import CF_TYPE_SELECT, CustomField, CustomFieldChoice, CustomFieldValue
from extras.models import (
CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_SELECT, CustomField, CustomFieldChoice, CustomFieldValue,
)
#
@ -25,16 +28,30 @@ class CustomFieldsSerializer(serializers.BaseSerializer):
for field_name, value in data.items():
cf = custom_fields[field_name]
# Validate custom field name
if field_name not in custom_fields:
raise ValidationError("Invalid custom field for {} objects: {}".format(content_type, field_name))
# Validate boolean
if cf.type == CF_TYPE_BOOLEAN and value not in [True, False, 1, 0]:
raise ValidationError("Invalid value for boolean field {}: {}".format(field_name, value))
# Validate date
if cf.type == CF_TYPE_DATE:
try:
datetime.strptime(value, '%Y-%m-%d')
except ValueError:
raise ValidationError("Invalid date for field {}: {}. (Required format is YYYY-MM-DD.)".format(
field_name, value
))
# Validate selected choice
cf = custom_fields[field_name]
if cf.type == CF_TYPE_SELECT:
valid_choices = [c.pk for c in cf.choices.all()]
if value not in valid_choices:
raise ValidationError("Invalid choice ({}) for field {}".format(value, field_name))
raise ValidationError("Invalid choice for field {}: {}".format(field_name, value))
# Check for missing required fields
missing_fields = []
@ -87,7 +104,7 @@ class CustomFieldModelSerializer(serializers.ModelSerializer):
field=custom_field,
obj_type=content_type,
obj_id=instance.pk,
defaults={'serialized_value': value},
defaults={'serialized_value': custom_field.serialize_value(value)},
)
def create(self, validated_data):

View File

@ -139,7 +139,11 @@ class CustomField(models.Model):
if self.type == CF_TYPE_BOOLEAN:
return str(int(bool(value)))
if self.type == CF_TYPE_DATE:
return value.strftime('%Y-%m-%d')
# Could be date/datetime object or string
try:
return value.strftime('%Y-%m-%d')
except AttributeError:
return value
if self.type == CF_TYPE_SELECT:
# Could be ModelChoiceField or TypedChoiceField
return str(value.id) if hasattr(value, 'id') else str(value)