tododrf序列化正确抛出异常,给前端
class BaseSerializer(Field): def is_valid(self, raise_exception=False):
assert not hasattr(self, "restore_object"), (
"Serializer `%s.%s` has old-style version 2 `.restore_object()` "
"that is no longer compatible with REST framework 3. "
"Use the new-style `.create()` and `.update()` methods instead." %
(self.__class__.__module__, self.__class__.__name__)
)
assert hasattr(self, "initial_data"), (
"Cannot call `.is_valid()` as no `data=` keyword argument was "
"passed when instantiating the serializer instance."
)
if not hasattr(self, "_validated_data"):
try:
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
self._validated_data = {}
self._errors = exc.detail
else:
self._errors = {}
if self._errors and raise_exception:
raise ValidationError(self.errors)
return not bool(self._errors)
默认验证 to_internal_value
class Serializer(BaseSerializer, metaclass=SerializerMetaclass): default_error_messages = {
"invalid": _("Invalid data. Expected a dictionary, but got {datatype}.")
}
@cached_property
def fields(self):
"""
A dictionary of {field_name: field_instance}.
"""
# `fields` is evaluated lazily. We do this to ensure that we don"t
# have issues importing modules that use ModelSerializers as fields,
# even if Django"s app-loading stage has not yet run.
fields = BindingDict(self)
for key, value in self.get_fields().items():
fields[key] = value
return fields
@property
def _writable_fields(self):
for field in self.fields.values():
if not field.read_only:
yield field
@property
def _readable_fields(self):
for field in self.fields.values():
if not field.write_only:
yield field
def get_fields(self):
"""
Returns a dictionary of {field_name: field_instance}.
"""
# Every new serializer is created with a clone of the field instances.
# This allows users to dynamically modify the fields on a serializer
# instance without affecting every other serializer instance.
return copy.deepcopy(self._declared_fields)
def get_validators(self):
"""
Returns a list of validator callables.
"""
# Used by the lazily-evaluated `validators` property.
meta = getattr(self, "Meta", None)
validators = getattr(meta, "validators", None)
return list(validators) if validators else []
def get_initial(self):
if hasattr(self, "initial_data"):
# initial_data may not be a valid type
if not isinstance(self.initial_data, Mapping):
return OrderedDict()
return OrderedDict([
(field_name, field.get_value(self.initial_data))
for field_name, field in self.fields.items()
if (field.get_value(self.initial_data) is not empty) and
not field.read_only
])
return OrderedDict([
(field.field_name, field.get_initial())
for field in self.fields.values()
if not field.read_only
])
def get_value(self, dictionary):
# We override the default field access in order to support
# nested HTML forms.
if html.is_html_input(dictionary):
return html.parse_html_dict(dictionary, prefix=self.field_name) or empty
return dictionary.get(self.field_name, empty)
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.
"""
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
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, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value
def _read_only_defaults(self):
fields = [
field for field in self.fields.values()
if (field.read_only) and (field.default != empty) and (field.source != "*") and ("." not in field.source)
]
defaults = OrderedDict()
for field in fields:
try:
default = field.get_default()
except SkipField:
continue
defaults[field.field_name] = default
return defaults
def run_validators(self, value):
"""
Add read_only fields with defaults to value before running validators.
"""
if isinstance(value, dict):
to_validate = self._read_only_defaults()
to_validate.update(value)
else:
to_validate = value
super().run_validators(to_validate)
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
if not isinstance(data, Mapping):
message = self.error_messages["invalid"].format(
datatype=type(data).__name__
)
raise ValidationError({
api_settings.NON_FIELD_ERRORS_KEY: [message]
}, code="invalid")
ret = OrderedDict()
errors = OrderedDict()
fields = self._writable_fields
# 针对每一个字段进行验证.
for field in fields:
validate_method = getattr(self, "validate_" + field.field_name, None)
primitive_value = field.get_value(data)
try:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
return ret
serializers.py 用户自定义的 def validate(self, attrs)
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.
"""
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
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, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value
def as_serializer_error(exc):
assert isinstance(exc, (ValidationError, DjangoValidationError))
if isinstance(exc, DjangoValidationError):
detail = get_error_detail(exc)
else:
detail = exc.detail
if isinstance(detail, Mapping):
# If errors may be a dict we use the standard {key: list of values}.
# Here we ensure that all the values are *lists* of errors.
return {
key: value if isinstance(value, (list, Mapping)) else [value]
for key, value in detail.items()
}
elif isinstance(detail, list):
# Errors raised as a list are non-field errors.
return {
api_settings.NON_FIELD_ERRORS_KEY: detail
}
# Errors raised as a string are non-field errors.
return {
api_settings.NON_FIELD_ERRORS_KEY: [detail]
}
以上是 tododrf序列化正确抛出异常,给前端 的全部内容, 来源链接: utcz.com/z/511495.html