zoukankan      html  css  js  c++  java
  • DRF之序列化器组件

    DRF之Serializer序列化组件

    简单介绍和快速配置

    序列化组件介绍

    drf中重要的一个组件,有以下三个大功能

    1. 序列化:序列化器会把数据库中查找得到的QuerySet对象转换成字典,经过response以后变成json字符串
    2. 反序列化:把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
    3. 反序列化:对数据进行校验,与form组件很像

    下面按照三个功能依次讲serializer的简单使用

    序列化简单使用

    • 为了演示例子,先建立一个库,写一张表,创建一个路由。以图书单表为例,书名、出版社、作者、价格。代码略
    • 在应用下新建一个py文件,用于放序列化器的代码,和form组件一样
    • 导入Serializer,书写序列化类继承Serializer,在类中写要序列化的字段,想序列化哪个字段,就在类中写哪个字段
    • 在views中使用,导入实例化得到序列化类的对象,把要序列化的对象传入
    • 序列化类的对象.data 是一个字典
    • 使用drf的response返回对象.data,或者使用Jsonresponse返回
    # urls.py
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^book/(?P<pk>d+)$', views.Book.as_view()),
        # 使用有名分组接收pk,注意url的最后没有斜杠/
    ]
    
    # views.py
    from rest_framework.views import APIView
    # 使用drf的apiview
    from app01 import models
    from app01 import ser
    # 导入序列化器
    from rest_framework.response import Response
    # 使用drf的response,可以在浏览器生成一个接口测试页面
    
    class Book(APIView):
        def get(self, request, pk):
            book_obj = models.Book.objects.filter(id=pk).first()
            # 首先从数据库中获取数据,得到一个模型类对象
            book_ser = ser.BookSerialize(book_obj)
            # 模型类对象传入序列化器,生成一个序列化器对象
            print(book_ser.data)
            # 我们希望返回的字典就在序列化器对象的data中
            return Response(book_ser.data)
    

    反序列化保存和校验数据

    案例,使用PUT,对书本表中的数据进行修改,前端发来的数据,我们需要进行校验,校验后存进数据库中。校验的步骤和form组件很像

    1. 写一个序列化的类,继承Serializer,在类中写要反序列化的字段

      max_length	最大长度
      min_lenght	最小长度
      allow_blank	是否允许为空
      trim_whitespace	是否截断空白字符
      max_value	最小值
      min_value	最大值
      
    2. 在视图类中使用,导入序列化器,实例化得到序列化类的对象,把要修改的对象传入,修改的数据传入

      boo_ser=BookSerializer(book,request.data)
      # book:要修改的对象,request:修改的参数
      boo_ser=BookSerializer(instance=book,data=request.data)
      # 这样写也可以,源码中的形参就是默认参数
      
    3. 数据校验 if boo_ser.is_valid()

    4. 如果校验通过,就保存

      boo_ser.save()  # 注意不是book.save()
      # 对传入了模型类的序列化器对象保存
      # 会触发底层的update方法,这个方法需要我们在序列化器类中重写
      
    5. 如果字段的校验规则不够,可以写钩子函数(局部和全局)

    注意

    在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。

    在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。也就是说,上面在获取数据的时候创建的序列化,在这一步可以直接拿来使用,是一个东西

    因为无法保证反序列化时操作的数据字段名和数据库中的字段名相同,drf的序列化器规定,关于反序列化后保存数据的操作,必须在序列化器类中重写一些方法:

    • create

    • update

      class BookInfoSerializer(serializers.Serializer):
          """图书数据序列化器"""
          def create(self, validated_data):
              """新建"""
              return BookInfo.objects.create(**validated_data)
      
          def update(self, instance, validated_data):
             ...
              return instance
      

    代码书写

    ser.py

    class BookSerializer(Serializer):
        title = serializers.CharField(max_length=10, min_length=2)
        price = serializers.DecimalField(decimal_places=2, max_digits=5)
        author = serializers.CharField(max_length=10, min_length=2)
        # 序列化器中的参数本身就是校验了
    
    	# 注意要重写update方法,返回instance
        def update(self, instance, validated_data):
        # 形参是pycharm自动生成的
            instance.title = validated_data.get('title')
            # 从校验通过的数据里面拿新的要更改的数据
            instance.price = validated_data.get('price')
            instance.author = validated_data.get('author')
            instance.save()
            return instance
    

    views.py

    class Book(APIView):
        def get(self, request, pk):
            ...
        def put(self, request, pk):
            response_msg = {'status': 100, 'msg': '成功'}
            # 通过url有名分组中的pk找到这个对象
            book = models.Book.objects.filter(id=pk).first()
            print(request.data)
            boo_ser = ser.BookSerializer(instance=book, data=request.data)
            # 执行is_valid()方法,对数据验证(同form表单的验证)
            if boo_ser.is_valid():  # 返回True表示验证通过
                boo_ser.save()  # 如果没有重写update,就会报错
                response_msg['data'] = boo_ser.data
            else:
                response_msg['status'] = 101
                response_msg['msg'] = '数据校验失败'
                response_msg['data'] = boo_ser.errors
            return Response(response_msg)
    

    钩子函数

    在序列化器中已经有一些参数可以对数据进行校验,除此之外还可以写钩子函数进一步校验,写法与form组件基本一样

    def validate_price(self, data):  
    	# 局部钩子:validate_字段名,data就是这个字段的值
    	if float(data) > 10:
    		# 判断价格大于10,通过校验
    		return data
    	else:
    		# 校验失败,抛异常,记得要导入模块
    		raise ValidationError('价格太低')
    
    def validate(self, validate_data):
    	# 全局钩子:所有的数据都在validate_data里,通过get取出来
    	print(validate_data)
    	author = validate_data.get('author')
    	title = validate_data.get('title')
    	if author == title:
    		raise ValidationError('作者名字跟书名一样')
    	else:
    		return validate_data
    

    还有别的校验数据的方法,validators=[]...,不过用的很少

    read_only和write_only

    在序列化和反序列化的时候,未必所有场景都像上面的案例一样,序列化和反序列化的时候字段都是一样的,比如自动生成的id

    在序列化类中给字段加上read_only和write_only,可以指定这些字段只在序列化或反序列化中有校验作用

    read_only	表明该字段仅用于序列化输出,默认False,如果设置成True,postman中可以看到该字段,修改时,不需要传该字段
    write_only	表明该字段仅用于反序列化输入,默认False,如果设置成True,postman中看不到该字段,修改时,该字段需要传
    
    # 以下的了解
    required	表明该字段在反序列化时必须输入,默认True
    default	反序列化时使用的默认值
    allow_null	表明该字段是否允许传入None,默认False
    validators	该字段使用的验证器
    error_messages	包含错误编号与错误信息的字典
    

    查询所有

    获取所有的书籍数据

    books = Book.objects.all()
    book_ser = BookSerializer(books,many=True)
    

    序列化多条数据需要加many这个参数,序列化一条不需要加。

    加上many和不加,得到的是两个不同种的对象

    POST新增数据

    与put一样,涉及到数据的保存,需要重写方法:create

    因为数据不放在url的pk中了,这次新创建一个url

    # urls.py
    url(r'^books/', views.Books.as_view()),
    
    # views.py
    class Books(APIView):
        def post(self, request):
            response_msg = {'status': 100, 'msg': '成功'}
            # 修改才有instance,新增没有instance,只有data
            book_ser = ser.BookSerializer(data=request.data)
            # book_ser = BookSerializer(request.data)  # 这个按位置传request.data会给instance,就报错了
            # 校验字段
            if book_ser.is_valid():
                book_ser.save()
                response_msg['data'] = book_ser.data
            else:
                response_msg['status'] = 102
                response_msg['msg'] = '数据校验失败'
                response_msg['data'] = book_ser.errors
            return Response(response_msg)
    
    # ser.py
    def create(self, validated_data):
        instance = models.Book.objects.create(
            title=validated_data.get('title'),
            price=validated_data.get('price'),
            author=validated_data.get('author'),
        )
        return instance
    # 最后一定要返回
    

    一直每个请求都要一个response_msg,可以把这个字典封装一下,放在utils里,要用的时候直接调用

    模型类序列化器

    之前写的序列化器,一直都是用的

    from rest_framework.serializers import Serializer
    

    除了这个之外,还有一个序列化器:

    from rest_framework.serializers import ModelSerializer
    

    如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

    ModelSerializer与常规的Serializer相同,但提供了:

    • 基于模型类自动生成一系列字段
    • 基于模型类自动为Serializer生成validators,比如unique_together
    • 包含默认的create()和update()的实现

    快速生成

    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = Book
            # models.py中的表名
            fields = '__all__'
            # fields=('name','price','id','author') # 只序列化指定的字段
            # exclude=('name',) #跟fields不能都写,写谁,就表示排除谁
            # read_only_fields=('price',)
            # write_only_fields=('id',) #弃用了,使用extra_kwargs
            extra_kwargs = {  # 类似于这种形式name=serializers.CharField(max_length=16,min_length=4)
                'price': {'write_only': True},
            }
    

    用模型类序列化器,不需要重写update和create方法了

    在views中的使用与Serializer一模一样

    Serializer高级用法

    # source的使用
    	1 可以改字段名字  xxx=serializers.CharField(source='title')
        2 可以.跨表publish=serializers.CharField(source='publish.email')
        3 可以执行方法pub_date=serializers.CharField(source='test') test是Book表模型中的方法
        
    
    # SerializerMethodField()的使用
    	1 它需要有个配套方法,方法名叫get_字段名,返回值就是要显示的东西
        authors=serializers.SerializerMethodField() #它需要有个配套方法,方法名叫get_字段名,返回值就是要显示的东西
        def get_authors(self,instance):
            # book对象
            authors=instance.authors.all()  # 取出所有作者
            ll=[]
            for author in authors:
                ll.append({'name':author.name,'age':author.age})
            return ll
    
  • 相关阅读:
    闭包函数与装饰器
    python 函数的参数
    python 函数定义及调用
    python 文件指针及文件覆盖
    phtnon 文件操作
    Volatile 关键字 内存可见性
    UNION 和 UNION ALL 操作符
    设计模式(七)---- 模板方法模式
    设计模式(六)---- 策略模式
    设计模式(五)---- 原型模式
  • 原文地址:https://www.cnblogs.com/telecasterfanclub/p/13263222.html
Copyright © 2011-2022 走看看