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

	
相关推荐
noravinsc9 小时前
django admin AttributeError: ‘UserResorce‘ object has no attribute ‘ID‘
数据库·django·sqlite
声声codeGrandMaster15 小时前
django之优化分页功能(利用参数共存及封装来实现)
数据库·后端·python·django
学c真好玩16 小时前
Django创建的应用目录详细解释以及如何操作数据库自动创建表
后端·python·django
沐暖沐16 小时前
Django(快速上手版)
python·django
@_猿来如此21 小时前
Django 实现电影推荐系统:从搭建到功能完善(附源码)
数据库·后端·python·django
noravinsc1 天前
django filter 排除字段
后端·python·django
noravinsc1 天前
django admin 设置字段不可编辑
django·filter·count·models
noravinsc1 天前
django filter 日期大于当前日期的
python·django
noravinsc1 天前
django admin 去掉新增 删除
python·django·sqlite
懵逼的小黑子1 天前
解释两个 Django 命令 makemigrations和migrate
数据库·django