Bootstrap

Django:DjangoRestFramework drf 开发3

7. 反序列化

反序列化有 验证保存 两个步骤。

1. 验证

实现步骤:

  1. 定义序列化器类型,根据模型类定义、写属性、类型、参数
  2. 创建序列化器对象,以请求报文中的字典为参数
  3. 调用 is_valid() 方法,如果验证通过则返回True,验证失败返回False
  4. 验证通过时可以调用 validated_data 获取验证后的数据
  5. 验证失败可以通过 error_messages 获取错误信息
  6. 指定参数 raise_exception=True 将错误继续抛出

验证有三种方法:根据属性类型、根据属性参数、自定义方法验证。

1. 根据属性的类型验证

CharField、EmailField、IntegerField、DateField等,用户输入类型错误会报属性的类型错误。

2. 属性参数验证

demo:

btitle = serializers.CharField(min_length=3,max_length=10,
							  error_messages={
                              	'min_length': '书名必须大于3个字符串',
                                'max_length': '书名必须小于10个字符串'})
bread = serializers.IntegerField(min_value=10, max_value=100)
id = serializers.IntegerField(read_only=True)
book_type = models.ForeignKey(Books, related_name='hero', on_delete=models.CASCADE, verbose_name='所属分类')  # 外键
# 主键和关系属性(外键)必须设成只读:read_only = True

3. 自定义方法进行验证

自定义方法验证有三种方式:

  • validate_属性名称() : 针对 特定(单个)属性的值进行验证

    # 验证书名的自定义方法<--在图书的序列化器内
    def validate_btitle(self, attr):
        # attr 是请求报文中书名的数据,比如 笑傲江湖
        # 要求: 书名中包含django字符串
        if 'django' in attr:
        	# 验证正常返回书名btitle
            return attr
        else:
            # 验证失败抛异常文本信息ValidationError
            raise serializers.ValidationError('书名中必须包含django')
    
  • validate() :针对多个值进行验证。内部参数是字典类型

    # 自定义验证方式二: 将多个属性进行验证
    def validate(self, attrs):
        # attrs 字典,可以接收所有请求报文中的数据
        # 多用于多个对比,验证: 阅读量必须大于评论量
        bread = attrs.get('bread')
        bcomment = attrs.get('bcomment')
        # 判断两个值都有才可以,request默认是True,我自己前边没指定,因此这个不用验证
        if all([bread, bcomment]):
            if bread < bcomment:
                raise serializers.ValidationError('阅读量必须大于评论量')
        return attrs
    
  • validators=[参数] :参数是方法列表,定义参数的函数,针对特定属性进行验证。(该方法用的不多)

    # 1.定义<---要把定义放到对应的序列化器上边
    def check(value):
        # 验证: value必须是偶数,只判断不符合要求的情况,抛异常,正常不用管
        if value % 2 != 0:
            raise serializers.ValidationError('必须为偶数')
    # 2.在序列化器中使用,对bread进行验证<--在bread限制条件内设置
    	# 因为是列表,因此可以写很多方法
    	validators=[check]
    

序列化器内定义反序列化的方法,然后在views视图内使用:

class BooksView(View):
	""" 图书类视图 """
    def post(self, request):
        # 接收
        params = json.loads(request.body.decode())
        # 把接收的数据赋给data参数
        book_ser = BookSerializer(data=params)
        # 验证(调用 is_valid() 方法进行验证)
        if book_ser.is_valid():
            # 验证成功(保存步骤中会在验证成功后保存,此处暂时返回被验证的数据)
            return JsonResponse(book_ser.validated_data)
        else:
            # 验证失败
            return JsonResponse(book_ser.errors)

2. 保存

实现步骤:

  1. 在序列化器中定义create()和update()方法
  2. 在视图中创建序列化器对象,调用is_valid()和save()方法

1. 调用序列化对象的save()方法完成保存

 serializer.save() 
  • save()方法包含createupdate方法,可以自动调用,这两个方法需要自己在序列化器中创建。
  • 如何知道save调用哪个方法:
    查看序列化器内的参数 BookSerializer(instance=None, data=None)
    • 有模型类对象instance,是update操作;
    • 没有模型类对象instance,是create操作。

2. 增加和修改之前先判断

  • 增加 create()

    当调用serializer.save()时,如果是增加就调用此方法,参数 validated_data 表示验证后的数据

    def create(self, validated_data):
    	# validated_data 表示验证后的数据,是字典类型 key:value
    	 # 拆包 **validated_data 拆成 key1:value1,key2:value2,...
    	 book = BookInfo.objects.create(**validated_data)
    	 return book
    

    视图函数中创建新增方法:

    class BooksView(View):
        """ 图书类视图 """
        def post(self, request):
            # 接收
            params = json.loads(request.body.decode())
            # 把接收的数据赋给data参数
            book_ser = BookSerializer(data=params)
            # 验证(调用 is_valid() 方法进行验证)
            if book_ser.is_valid():
                # 验证成功(调用序列化器的save()方法进行保存)
                book = book_ser.save()
                # 验证成功返回被验证的数据
                # return JsonResponse(book_ser.validated_data)
                # 保存成功之后返回新增的序列化器对象转成的字典数据
                book_dict = BookSerializer(book).data
                return JsonResponse(book_dict, status=201)
            else:
                # 验证失败
                return JsonResponse(book_ser.errors)
    
  • 修改 update()

    当调用serializer.save()时,如果是修改就调用此方法,参数 instance 需要被修改的对象,validated_data 验证后的数据

    def update(self, instance, validated_data):
    	# instance 需要被修改的对象, validated_data 验证后的数据
    	instance.btitle = validated_data.get('btitle')
    	instance.bpub_date = validated_data.get('bpub_date')
    	instance.save()
    	return instance
    

    视图函数中创建修改方法:

    class BookView(View):
    	""" 图书视图 """
        def put(self, request, pk):
            """ 根据主键修改 """
            params = json.loads(request.body.decode())
            book = Books.objects.get(pk=pk)
            # serializer = BookSerializer(instance=book, data=params)
            serializer = BookSerializer(book, data=params)  # instance是第一个参数,可以省略
            if serializer.is_valid():
                book = serializer.save()
                book_dict = BookSerializer(book).data
                return JsonResponse(book_dict, status=201)
            else:
                return JsonResponse(serializer.errors)
    
  • 说明:(param_dict接收到的数据)

    • 如果进行create添加操作,则serializer=**Serializer(data=param_dict)
    • 如果进行update修改操作,则serializer=**Serializer(模型类对象,data=param_dict)

知识点:

  • 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到:

    serializer.save(owner=request.user)
    
;