DRF序列化_data传参
instance传参时,序列化不能对数据进行校验,只有data传参时,才能同时校验和序列化
class User(models.Model):
name = models.CharField(max_length=16)
code = models.CharField(max_length=20)
class Meta:
db_table = "users_organizations"
managed = False
from rest_framework import serializers
class userSerialize(serializers.Serializer):
name = serializers.CharField(max_length=100)
code = serializers.CharField(max_length=100)
# 通常data是我们从请求中获取的数据,是我们要存入数据库的数据,所以我们需要对要存入数据库的数据进行校验
data = {'name':'zs','code':'11'}
user_serialize = userSerialize(data=data)
1. 调用 ser_data .is_valid()
1. userSerialize.is_valide() 继承于 BaseSerializer
1. assert hasattr(self, 'initial_data'),如果没有 data参数没有传参,不允许调用 is_valid()函数
2.self.initial_data 等于data,进入到 self.run_validation
BaseSerializer(Field):
def is_valid(self, *, raise_exception=False):
# 如果没有 data参数没有传参,不允许调用 is_valid()函数
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)
2. 进入到 Serializer.run_validation
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
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
3. 进入到 Field.validate_empty_values
1.调用的是 字段的 validate_empty_values,调用 validate_empty_values时,self指的就是这个字段的实例化
2. self.read_only 如果这个字段被设置的是只读字段,那们就不需要校验,直接返回是控制,只读字段是不需要传入数据存入到数据库的
3. 如果data不为空,返回False 和 data
class Field:
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:
self.fail('null')
# 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)
4. 继续回到 Serializer.run_validation
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
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.
"""
# 验证data不为空
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
# 来到 to_internal_value
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
5. 来到 Serializer.to_internal_value
1. if not isinstance(data, Mapping) 如果数据不是Mapping数据类型,则是无效的数据格式
2. 来到 Serializer._writable_fields
3. fields = self._writable_fields fields是一个生成器
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
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
6. 来到 Serializer._writable_fields
1. 排除只读字段
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
@property
def _writable_fields(self):
for field in self.fields.values():
if not field.read_only:
yield field
7. 来到 Serializer.fields
1.返回一个 BindingDict容器
2.容器中加入了对应的 字段名称 和 字段对应的 实例化类
3.BindingDict 可以直接通过键取值,走的是 __getitem__ 魔术函数
4. 对 BindingDict 进行迭代时 走的是 __iter__ 魔术函数
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
@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.
# 在 instance 中传参已经写过相关部分
fields = BindingDict(self)
for key, value in self.get_fields().items():
fields[key] = value
return fields
class BindingDict(MutableMapping):
"""
This dict-like object is used to store fields on a serializer.
This ensures that whenever fields are added to the serializer we call
`field.bind()` so that the `field_name` and `parent` attributes
can be set correctly.
"""
def __init__(self, serializer):
self.serializer = serializer
self.fields = OrderedDict()
def __setitem__(self, key, field):
self.fields[key] = field
field.bind(field_name=key, parent=self.serializer)
def __getitem__(self, key):
return self.fields[key]
def __delitem__(self, key):
del self.fields[key]
def __iter__(self):
return iter(self.fields)
def __len__(self):
return len(self.fields)
def __repr__(self):
return dict.__repr__(self.fields)
8. 回到 Serializer.to_internal_value
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
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是一个生成器
fields = self._writable_fields
for field in fields:
# 看看自定义类中有哪些字段自定义了 validate_field_name的方法,获取自定义方法
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
9. Field.get_value()
1. html.is_html_input(dictionary) dictionary是输入传入的data参数,如果是在html中输入的数据,则对输入的数据进行处理
2. 不是html页面输入的数据,则直接取 对应fild_name对应的值,没有则返回empty
class Field:
def get_value(self, dictionary):
"""
Given the *incoming* primitive data, return the value for this field
that should be validated and transformed to a native value.
"""
if html.is_html_input(dictionary):
# HTML forms will represent empty fields as '', and cannot
# represent None or False values directly.
if self.field_name not in dictionary:
if getattr(self.root, 'partial', False):
return empty
return self.default_empty_html
ret = dictionary[self.field_name]
if ret == '' and self.allow_null:
# If the field is blank, and null is a valid value then
# determine if we should use null instead.
return '' if getattr(self, 'allow_blank', False) else None
elif ret == '' and not self.required:
# If the field is blank, and emptiness is valid then
# determine if we should use emptiness instead.
return '' if getattr(self, 'allow_blank', False) else empty
return ret
return dictionary.get(self.field_name, empty)
10. 回到 Serializer.to_internal_value:
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
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是一个生成器
fields = self._writable_fields
for field in fields:
# 看看自定义类中有哪些字段自定义了 validate_field_name的方法,获取自定义方法
validate_method = getattr(self, 'validate_' + field.field_name, None)
# 在data中根据 field.field_name取值,如果是空值则做相应的处理
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
11. 来到 Field.run_validation
1. 目标是对每个字段内的配置的校验规则进行验证
class Field:
def run_validation(self, data=empty):
"""
Validate a simple representation and return the internal value.
The provided data may be `empty` if no representation was included
in the input.
May raise `SkipField` if the field should not be included in the
validated data.
"""
# 校验data是否为空,data是field 对应的字段值
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
value = self.to_internal_value(data)
self.run_validators(value)
return value
12. 来到 Field.to_internal_value(value)
假设是 CharField
1.将对应的值转换为字符串
class CharField(Field):
def to_internal_value(self, data):
# We're lenient with allowing basic numerics to be coerced into strings,
# but other types should fail. Eg. unclear if booleans should represent as `true` or `True`,
# and composites such as lists are likely user error.
if isinstance(data, bool) or not isinstance(data, (str, int, float,)):
self.fail('invalid')
value = str(data)
return value.strip() if self.trim_whitespace else value
13. 回到 Field.run_validation
class Field:
def run_validation(self, data=empty):
"""
Validate a simple representation and return the internal value.
The provided data may be `empty` if no representation was included
in the input.
May raise `SkipField` if the field should not be included in the
validated data.
"""
# 校验data是否为空,data是field 对应的字段值
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
# 如果对应的field字段Charfield,那么就是将值转换为字符串,将值进行序列化
value = self.to_internal_value(data)
self.run_validators(value)
return value
14. 来到 Field.run_validators()
1. 如果报错,那么就会抛出错误
class Field:
def run_validators(self, value):
"""
Test the given value against all the validators on the field,
and either raise a `ValidationError` or simply return.
"""
errors = []
for validator in self.validators:
try:
if getattr(validator, 'requires_context', False):
validator(value, self)
else:
validator(value)
except ValidationError as exc:
# If the validation error contains a mapping of fields to
# errors then simply raise it immediately rather than
# attempting to accumulate a list of errors.
if isinstance(exc.detail, dict):
raise
errors.extend(exc.detail)
except DjangoValidationError as exc:
errors.extend(get_error_detail(exc))
if errors:
raise ValidationError(errors)
15. 来到 Field.validators
如果kwargs中传入了 validators = ...,在调用 super().__init__(**kwargs) 时,会用 Field.__init__来初始化
如果传了validators,就用传入的validators,没有传则就用默认的validators,这个也要自己指明
class CharField(Field):
def __init__(self, **kwargs):
super().__init__(**kwargs)
class Field:
def __init__(self, *, read_only=False, write_only=False,
required=None, default=empty, initial=empty, source=None,
label=None, help_text=None, style=None,
error_messages=None, validators=None, allow_null=False):
if validators is not None:
self.validators = list(validators)
16. 回到 10 Serializer.to_internal_value:
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
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是一个生成器
fields = self._writable_fields
for field in fields:
# 看看自定义类中有哪些字段自定义了 validate_field_name的方法,获取自定义方法
validate_method = getattr(self, 'validate_' + field.field_name, None)
# 在data中根据 field.field_name取值,如果是空值则做相应的处理
primitive_value = field.get_value(data)
try:
# 对field字段内配置的规则对值进行校验,字段内配置的规则通常是我们传参数传入进去的
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:
# 如果try中没有报错则走这一步,把字段名和字段值都更新到ret中
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
#
return ret
17、 回到 4 Serializer.run_validation
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
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.
"""
# 验证data不为空
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
# value是一个经过检验的字典,键是字段名,值是字段值
value = self.to_internal_value(data)
try:
# 这个self指的是自定义的序列化类,因次我们可以在类属性中自定义序列化类 validators
self.run_validators(value)
# validate 继承于 Serializer,如果不重新定义validate,那么返回是自己本身的值
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
18、来到self.run_validators,run_validators 继承自Field,
1、这个self指的是自定义的序列化类,因次我们可以在类属性中自定义序列化类 validators
class Field:
def run_validators(self, value):
"""
Test the given value against all the validators on the field,
and either raise a `ValidationError` or simply return.
"""
errors = []
for validator in self.validators:
try:
if getattr(validator, 'requires_context', False):
validator(value, self)
else:
validator(value)
except ValidationError as exc:
# If the validation error contains a mapping of fields to
# errors then simply raise it immediately rather than
# attempting to accumulate a list of errors.
if isinstance(exc.detail, dict):
raise
errors.extend(exc.detail)
except DjangoValidationError as exc:
errors.extend(get_error_detail(exc))
if errors:
raise ValidationError(errors)
19、 class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
def validate(self, attrs):
return attrs
20、回到 1
BaseSerializer(Field):
def is_valid(self, *, raise_exception=False):
# 如果没有 data参数没有传参,不允许调用 is_valid()函数
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 为空
self._errors = {}
if self._errors and raise_exception:
raise ValidationError(self.errors)
不报错,返回的就是True
return not bool(self._errors)
2、ser_data .is_valid() 验证总结
进入Serializer.run_validation,在run_validation中做了如下几件事
1. 首先获取字段的值
2. 先用字段内传入的validators进行校验
3. 检查每个字段是否写了 validate_字段名 方法,如果有那么对字段值进行校验
4. 如果自定义的序列化类中,类属性定义了validators,有validators对传入的字典值(包括所有字段的值)进行综合的校验
5. 如果自定义了validate,那么就用validate,对所有的字段值进行校验(传入的值是字典,包括所有的字段值)
3、验证完后,获取 ser_data .data,
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
@property
def data(self):
# print('self测试。。。。',self)
ret = super().data
# print('ret测试。。。。',ret)
return ReturnDict(ret, serializer=self)
class BaseSerializer(Field):
@property
def data(self):
print('base self....',self)
print('base self....', self.__class__)
if hasattr(self, 'initial_data') and not hasattr(self, '_validated_data'):
msg = (
'When a serializer is passed a `data` keyword argument you '
'must call `.is_valid()` before attempting to access the '
'serialized `.data` representation.\n'
'You should either call `.is_valid()` first, '
'or access `.initial_data` instead.'
)
raise AssertionError(msg)
if not hasattr(self, '_data'):
if self.instance is not None and not getattr(self, '_errors', None):
self._data = self.to_representation(self.instance)
# 对validated_data进行序列化,之后的过程 跟instance传参一样的步骤
elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
self._data = self.to_representation(self.validated_data)
else:
self._data = self.get_initial()
return self._data
4、验证完后可以直接获取 validated_data ,因为校验之前,已经序列化过了,没有必要再调data了
在 is_valid()中第13步的时候,已经将值进行序列化了
class BaseSerializer(Field):
@property
def validated_data(self):
if not hasattr(self, '_validated_data'):
msg = 'You must call `.is_valid()` before accessing `.validated_data`.'
raise AssertionError(msg)
return self._validated_data