def _get_attribute(self, instance): # Can't have any relationships if not created if hasattr(instance, 'pk') and instance.pk is None: return [] try: relationship = get_attribute(instance, self.source_attrs) except (KeyError, AttributeError) as exc: if self.default is not empty: return self.get_default() if self.allow_null: return None if not self.required: raise SkipField() msg = ('Got {exc_type} when attempting to get a value for field ' '`{field}` on serializer `{serializer}`.\nThe serializer ' 'field might be named incorrectly and not match ' 'any attribute or key on the `{instance}` instance.\n' 'Original exception text was: {exc}.'.format( exc_type=type(exc).__name__, field=self.field_name, serializer=self.parent.__class__.__name__, instance=instance.__class__.__name__, exc=exc, )) raise type(exc)(msg) return relationship.all() if hasattr(relationship, 'all') else relationship
def to_internal_value(self, data): # Skip http/https urls to avoid overwriting valid data when, for example, a client GETs and subsequently PUTs an # entity containing an image URL. if self.skip_http and not isinstance(data, UploadedFile) and urlparse.urlparse(data).scheme in ('http', 'https'): raise SkipField() return super(ValidImageField, self).to_internal_value(data)
def to_internal_value(self, data): required = kwargs.get('required', True) default = kwargs.get('default', empty) if data == empty: # Implementation under this block is made # according to DRF behaviour to other normal fields # For more details see # https://www.django-rest-framework.org/api-guide/fields/#required # https://www.django-rest-framework.org/api-guide/fields/#default # https://www.django-rest-framework.org/api-guide/fields/#allow_null if self.root.partial or not required: # Skip the field because the update is partial # or the field is not required(optional) raise SkipField() elif required: if default == empty: raise ValidationError( "This field is required.", code='required' ) else: # Use the default value data = default if accept_pk_only: return self.run_pk_validation(data) elif accept_pk: if isinstance(data, dict): self.is_replaceable = False return self.run_data_validation(data) else: return self.run_pk_validation(data) return self.run_data_validation(data)
def to_representation(self, instance): request = self._get_request() fields = self._readable_fields ret = OrderedDict() # Get fields that the user is allowed to view. allowed_fields = self.Meta.field_permissions.get_permitted_field_names( action='view', obj=instance, user=request.user) # Skip fields that the user is not allowed to view. Use the SkipField # exception because `field.get_attribute` can also raise that. for field in fields: try: if field.field_name not in allowed_fields: raise SkipField() attribute = field.get_attribute(instance) except SkipField: continue # Filter related objects that are None as we don't have to serialize # them. check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute ret[field.field_name] = None if check_for_none is None else field.to_representation(attribute) return ret
def get_attribute(self, instance): value = serializers.Field.get_attribute(self, instance) if value == '' or value is None or value == {}: if not self.required or not self.allow_blank: raise SkipField() return value
def validate_empty_values(self, data): """ Validate empty values, and either: * Raise `ValidationError`, indicating invalid data. * Raise `SkipField`, indicating that the field should be ignored. * Return (True, data), indicating an empty value that should be returned without any further validation being applied. * Return (False, data), indicating a non-empty value, that should have validation applied as normal. """ if self.read_only: return (True, self.get_default()) if data is empty: if getattr(self.root, "partial", False): raise SkipField() if self.required: self.fail("required") return (True, self.get_default()) if data is None: if not self.allow_null: raise serializers.ValidationError( strings.Addresses.NULL_COUNTRY) # Nullable `source='*'` fields should not be skipped when its named # field is given a null value. This is because `source='*'` means # the field is passed the entire object, which is not null. elif self.source == "*": return (False, None) return (True, None) return (False, data)
def to_representation(self, instance, row_data=None): """ Object instance -> Dict of primitive datatypes. """ ret = OrderedDict() for field in self._readable_fields: try: attribute = field.get_attribute(instance) if not isinstance(field, RenderMixin): ret[field.field_name] = field.to_representation(attribute) else: try: ret[field.field_name] = field.to_representation( attribute, instance) except: if attribute is None and not field.required: # DRF makes a special check for none and then always returns None if the check is None. # We still want to process custom field to_representation, even if value is None. # But when field is a sub-serializer and it (it's FK reference) is none, it's OK # to pass None as result of serialization of such field raise SkipField() else: raise except SkipField: pass return ret
def __call__(self): if hasattr(self, 'is_update') and self.is_update: # TODO: Make sure this check is sufficient for all update scenarios raise SkipField() user = super(CreateOnlyCurrentUserDefault, self).__call__() if user and user.is_authenticated(): return user return None
def enforce_required_fields(self, attrs, serializer): try: super(OptionalUniqueTogetherValidator, self).enforce_required_fields(attrs, serializer) except ValidationError as e: if set(e.detail.keys()) == set(self.fields): raise SkipField() else: raise
def to_internal_value(self, data): """ List of dicts of native values <- List of dicts of primitive datatypes. """ if not self.instance: return super().to_internal_value(data) if html.is_html_input(data): data = html.parse_html_list(data) if not isinstance(data, list): message = self.error_messages['not_a_list'].format( input_type=type(data).__name__ ) raise ValidationError({ api_settings.NON_FIELD_ERRORS_KEY: [message] }, code='not_a_list') if not self.allow_empty and len(data) == 0: if self.parent and self.partial: raise SkipField() message = self.error_messages['empty'] raise ValidationError({ api_settings.NON_FIELD_ERRORS_KEY: [message] }, code='empty') ret = [] errors = [] for item in data: try: # prepare child serializer to only handle one instance if 'id' in item: pk = item["id"] elif 'pk' in item: pk = item["pk"] else: raise ValidationError("id or pk not in data") child = self.instance.get(id=pk) if self.instance else None self.child.instance = child self.child.initial_data = item # raw validated = self.child.run_validation(item) except ValidationError as exc: errors.append(exc.detail) except ObjectDoesNotExist as e: errors.append(e) else: ret.append(validated) errors.append({}) if any(errors): raise ValidationError(errors) return ret
def get_attribute(self, instance): # When handling the create() all, skip this field. if isinstance(instance, (dict, OrderedDict)): raise SkipField() assert isinstance(instance, TranslatedFieldsModel), (( "The TranslatedAbsoluteUrlField can only be used on a TranslatableModelSerializer, " " not on a {0}".format(instance.__class__))) return instance
def run_validation(self, data): # Reject empty strings only if field is required. # Otherwise SkipField on encountering an empty string. if data == '': if not self.allow_blank and not self.required: raise SkipField() elif not self.allow_blank: self.fail('blank') return '' return super(serializers.CharField, self).run_validation(data)
def to_internal_value(self, data): # Skip http/https urls to avoid overwriting valid data when, for example, a client GETs and subsequently PUTs an # entity containing an image URL. if self.skip_http and not isinstance( data, UploadedFile) and urllib.parse.urlparse(data).scheme in ( 'http', 'https'): raise SkipField() self.source_attrs = [ 'image' ] # Kind of a dirty hack, because this is failing to stick if set on init. return super(ValidImageField, self).to_internal_value(data)
def to_internal_value(self, obj): if obj in self.EMPTY_VALUES: return None elif isinstance(obj, str): if obj.startswith('http'): raise SkipField() media_url = getattr(settings, 'MEDIA_URL', None) if media_url and obj.startswith(media_url): raise SkipField() elif isinstance(obj, dict): if not all(key in obj for key in ('file_name', 'encoded_str')): raise ValidationError(self.INVALID_OBJECT) try: self.name, self.ext = obj['file_name'].rsplit('.', 1) except ValueError: raise ValidationError(self.INVALID_FILE_NAME) if self.ext not in self.ALLOWED_TYPES and self.ALLOW_ALL_EXTENSIONS: self.ALLOWED_TYPES.append(self.ext) encoded_str = obj['encoded_str'] return super().to_internal_value(encoded_str) elif isinstance(obj, UploadedFile): try: self.name = obj.name self.size = obj.size except AttributeError: raise ValidationError(self.INVALID_FILE_UPLOAD) try: _, self.ext = self.name.rsplit('.', 1) except ValueError: raise ValidationError(self.INVALID_FILE_NAME) if self.ext not in self.ALLOWED_TYPES and not self.ALLOW_ALL_EXTENSIONS: raise ValidationError(self.INVALID_TYPE_MESSAGE) return obj else: raise ValidationError(self.INVALID_DATA)
def validate_empty_values(self, data): """ If an empty value (empty string, null) exists in an optional field, SkipField. """ (is_empty_value, data) = serializers.Field.validate_empty_values(self, data) if is_empty_value or data == '': if self.required: self.fail('required') raise SkipField() return (False, data)
def run_validation(self, data=empty): """ We override the default `run_validation`, because the validation performed by validators and the `.validate()` method should be coerced into an error dictionary with a 'non_fields_error' key. """ if data is empty: if getattr(self.root, 'partial', False): raise SkipField() if self.required: self.fail('required') return self.get_default() if data is None: if not self.allow_null: self.fail('null') return None if not isinstance(data, dict): message = self.error_messages['invalid'].format( datatype=type(data).__name__) raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: [message]}) value = self.to_internal_value(data) try: self.run_validators(value) value = self.validate(value) assert value is not None, '.validate() should return the validated data' except ValidationError as exc: if isinstance(exc.detail, dict): # .validate() errors may be a dict, in which case, use # standard {key: list of values} style. raise ValidationError( dict([(key, value if isinstance(value, list) else [value]) for key, value in exc.detail.items()])) elif isinstance(exc.detail, list): raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: exc.detail}) else: raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: [exc.detail]}) except DjangoValidationError as exc: # Normally you should raise `serializers.ValidationError` # inside your codebase, but we handle Django's validation # exception class as well for simpler compat. # Eg. Calling Model.clean() explictily inside Serializer.validate() raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: list(exc.messages)}) return value
def to_internal_value(self, data): if not isinstance(data, str): raise ValidationError("uploaded-file-invalid-uploaded-file") try: uuid.UUID(data) return self.fetch_file_or_error(data) except ValueError: if not data.startswith("http://") and not data.startswith( "https://"): raise ValidationError("uploaded-file-invalid-uuid") # Storing the value again, without changes: This is expected to be the original URL raise SkipField()
def _decode(self, data): if is_text(data) and data.startswith('data:'): # base64 encoded file - decode format, datastr = data.split(';base64,') # format ~= data:image/X, ext = format.split('/')[-1] # guess file extension if ext[:3] == 'svg': ext = 'svg' data = ContentFile(base64.b64decode(datastr), name='{}.{}'.format(uuid.uuid4(), ext)) elif is_text(data) and data.startswith('http'): raise SkipField() return data
def validate_empty_values(self, data): """ Validate empty values, and either: * Raise `ValidationError`, indicating invalid data. * Raise `SkipField`, indicating that the field should be ignored. * Return (True, data), indicating an empty value that should be returned without any further validation being applied. * Return (False, data), indicating a non-empty value, that should have validation applied as normal. """ if not data or data is empty: raise SkipField() return super().validate_empty_values(data)
def to_internal_value(self, data): if not isinstance(data, dict): message = self.error_messages['not_a_dict'].format( input_type=type(data).__name__) raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: [message]}, code='not_a_dict') if not self.allow_empty and len(data) == 0: if self.parent and self.partial: raise SkipField() message = self.error_messages['empty'] raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: [message]}, code='empty') data = [{**v, **{self._keyed_field: k}} for k, v in data.items()] return super().to_internal_value(data)
def to_internal_value(self, data): """ List of dicts of native values <- List of dicts of primitive datatypes. """ if html.is_html_input(data): data = html.parse_html_list(data) if not isinstance(data, list): message = self.error_messages['not_a_list'].format( input_type=type(data).__name__) raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: [message]}, code='not_a_list') if not self.allow_empty and len(data) == 0: if self.parent and self.partial: raise SkipField() message = self.error_messages['empty'] raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: [message]}, code='empty') id_attr = getattr(self.child.Meta, 'update_lookup_field', 'id') ret = [] errors = [] for item in data: try: view = self.context.get('view') if view and view.action != 'create': if id_attr not in item: raise ValidationError( {id_attr: ['This field is required.']}) instance = self.instance.get(**{id_attr: item[id_attr]}) self.child.instance = instance self.child.initial_data = item # Until here validated = self.child.run_validation(item) except ValidationError as exc: errors.append(exc.detail) else: ret.append(validated) errors.append({}) return {'ret': ret, 'errors': errors}
def to_internal_value(self, data): """ List of dicts of native values <- List of dicts of primitive datatypes. """ if html.is_html_input(data): data = html.parse_html_list(data, default=[]) if not isinstance(data, list): message = self.error_messages['not_a_list'].format( input_type=type(data).__name__) raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: [message]}, code='not_a_list') if not self.allow_empty and len(data) == 0: if self.parent and self.partial: raise SkipField() message = self.error_messages['empty'] raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: [message]}, code='empty') ret = [] errors = [] for item in data: try: if self.instance: try: self.child.instance = self.instance.get(id=item['id']) self.child.initial_data = item except getattr(self.child.Meta.model, 'DoesNotExist') as exc: raise ValidationError({'non_field_errors': [str(exc)]}) validated = self.child.run_validation(item) except ValidationError as exc: errors.append(exc.detail) else: ret.append(validated) errors.append({}) if any(errors): raise ValidationError(errors) return ret
def get_attribute(self, instance): try: return get_attribute_smart(instance, self.source_attrs) except (KeyError, AttributeError) as exc: if not self.required and self.default is empty: raise SkipField() msg = ('Got {exc_type} when attempting to get a value for field ' '`{field}` on serializer `{serializer}`.\nThe serializer ' 'field might be named incorrectly and not match ' 'any attribute or key on the `{instance}` instance.\n' 'Original exception text was: {exc}.'.format( exc_type=type(exc).__name__, field=self.field_name, serializer=self.parent.__class__.__name__, instance=instance.__class__.__name__, exc=exc)) raise type(exc)(msg)
def _decode(self, data): if isinstance(data, str) and data.startswith("data:"): # base64 encoded file - decode # format ~= data:image/X, format, datastr = data.split(";base64,") ext = format.split("/")[-1] # guess file extension if ext[:3] == "svg": ext = "svg" data = ContentFile( base64.b64decode(datastr), name="{}.{}".format(uuid.uuid4(), ext) ) elif isinstance(data, str) and data.startswith("http"): raise SkipField() return data
def to_internal_value(self, data): """ List of dicts of native values <- List of dicts of primitive datatypes. """ if html.is_html_input(data): data = html.parse_html_list(data, default=[]) if not isinstance(data, list): message = self.error_messages['not_a_list'].format( input_type=type(data).__name__) raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: [message]}, code='not_a_list') if not self.allow_empty and len(data) == 0: if self.parent and self.partial: raise SkipField() message = self.error_messages['empty'] raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: [message]}, code='empty') ret = [] errors = [] id_attr = getattr(self.child.Meta, 'update_lookup_field', 'id') for item in data: try: # --------------------- patched pieces -------------------------------- self.child.instance = self.instance.get( **{id_attr: item.get(id_attr)}) self.child.initial_data = item # --------------------------------------------------------------------- validated = self.child.run_validation(item) except ValidationError as exc: errors.append(exc.detail) else: ret.append(validated) errors.append({}) if any(errors): raise ValidationError(errors) return ret
def to_internal_value(self, data): """ Body of run_validation for all data items """ if data is None: raise ValidationError('All tasks are empty (None)') if not isinstance(data, list): raise ValidationError( {api_settings.NON_FIELD_ERRORS_KEY: 'not a list'}, code='not_a_list') if not self.allow_empty and len(data) == 0: if self.parent and self.partial: raise SkipField() raise ValidationError({api_settings.NON_FIELD_ERRORS_KEY: 'empty'}, code='empty') ret, errors = [], [] self.annotation_count, self.prediction_count = 0, 0 for i, item in enumerate(data): try: validated = self.child.validate(item) except ValidationError as exc: error = self.format_error(i, exc.detail, item) errors.append(error) # do not print to user too many errors if len(errors) >= 100: errors[99] = '...' break else: ret.append(validated) errors.append({}) if 'annotations' in item: self.annotation_count += len(item['annotations']) if 'predictions' in item: self.prediction_count += len(item['predictions']) if any(errors): logger.warning("Can't deserialize tasks due to " + str(errors)) raise ValidationError(errors) return ret
def to_internal_value(self, obj): if obj in self.EMPTY_VALUES: return None elif isinstance(obj, str) and obj.startswith('http'): raise SkipField() elif isinstance(obj, dict): if not all(key in obj for key in ('file_name', 'encoded_str')): raise ValidationError(self.INVALID_OBJECT) try: self.name, self.ext = obj['file_name'].rsplit('.', 1) except ValueError: raise ValidationError(self.INVALID_FILE_NAME) if self.ext not in self.ALLOWED_TYPES and self.ALLOW_ALL_EXTENSIONS: self.ALLOWED_TYPES.append(self.ext) encoded_str = obj['encoded_str'] return super().to_internal_value(encoded_str) else: raise ValidationError(self.INVALID_DATA)
def validate_empty_values(self, data): """ Validate empty values, and either: * Raise `ValidationError`, indicating invalid data. * Raise `SkipField`, indicating that the field should be ignored. * Return (True, data), indicating an empty value that should be returned without any further validation being applied. * Return (False, data), indicating a non-empty value, that should have validation applied as normal. """ if data is empty: if getattr(self.root, 'partial', False): raise SkipField() if self.write_field.required: self.fail('required') return (True, self.get_default()) if data is None: if not self.write_field.allow_null: self.fail('null') return (True, None) return (False, data)
def get_attribute(self, instance): # xform is not an attribute of the MetaData object if instance and isinstance(instance.content_object, XForm): return instance.content_object raise SkipField()
def get_attribute(self, instance): val = get_object_id_by_content_type(instance, Instance) if val: return val raise SkipField()