DRF序列化_data传参

DRF序列化_data传参

  • [1. 调用 ser_data .is_valid()](#1. 调用 ser_data .is_valid())
  • [2、ser_data .is_valid() 验证总结](#2、ser_data .is_valid() 验证总结)
  • [3、验证完后,获取 ser_data .data,](#3、验证完后,获取 ser_data .data,)
  • [4、验证完后可以直接获取 validated_data ,因为校验之前,已经序列化过了,没有必要再调data了](#4、验证完后可以直接获取 validated_data ,因为校验之前,已经序列化过了,没有必要再调data了)

instance传参时,序列化不能对数据进行校验,只有data传参时,才能同时校验和序列化

python 复制代码
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()

python 复制代码
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,

python 复制代码
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步的时候,已经将值进行序列化了

python 复制代码
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

	
相关推荐
0zxm8 小时前
06 - Django 视图view
网络·后端·python·django
凡人的AI工具箱11 小时前
每天40分玩转Django:Django国际化
数据库·人工智能·后端·python·django·sqlite
isSamle1 天前
使用Vue+Django开发的旅游路书应用
前端·vue.js·django
╰つ゛木槿1 天前
Spring Boot与Django对比:哪个更适合做为Web服务器框架?
前端·spring boot·django
Null箘1 天前
从零创建一个 Django 项目
后端·python·django
江上挽风&sty1 天前
【Django篇】--动手实践Django基础知识
数据库·django·sqlite
云和数据.ChenGuang2 天前
Django 应用安装脚本 – 如何将应用添加到 INSTALLED_APPS 设置中 原创
数据库·django·sqlite
LuiChun2 天前
Django 模板分割及多语言支持案例【需求文档】-->【实现方案】
数据库·django·sqlite
凡人的AI工具箱2 天前
每天40分玩转Django:Django管理界面
开发语言·数据库·后端·python·django
中科院提名者2 天前
Django连接mysql数据库报错ModuleNotFoundError: No module named ‘MySQLdb‘
数据库·mysql·django