Django REST Framework(四)DRF Serializer

作用:

  1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串

  2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型

  3. 反序列化,完成数据校验功能

定义序列化器

  • Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。 接下来,为了方便演示序列化器的使用,我们先创建一个新的子应用sers

    python manage.py startapp sers
    
    python 复制代码
    from django.db import models
    
    
    # Create your models here.
    
    class Book(models.Model):
        title = models.CharField(max_length=32,verbose_name="书籍名称")
        price = models.IntegerField(verbose_name="价格")
        pub_date = models.DateField(verbose_name="出版日期")

    我们想为Book模型类提供一个序列化器,可以定义如下:

    python 复制代码
    from rest_framework import serializers
    
    class BookSerializer(serializers.Serializer):
        title = serializers.CharField()
        price = serializers.IntegerField()
        pub_date = serializers.DateField()

    **注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。**serializer是独立于数据库之外的存在。

创建Serializer对象

  • 定义好Serializer类后,就可以创建Serializer对象了。

    Serializer的构造方法为:Serializer(instance=None, data=empty, **kwarg)

  • 说明:

    • 用于序列化时,将模型类对象传入instance参数

    • 用于反序列化时,将要被反序列化的数据传入data参数

    • 除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如 serializer = AccountSerializer(account, context={'request': request})

  • 通过context参数附加的数据,可以通过Serializer对象的context属性获取。

    • 使用序列化器的时候一定要注意,序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。

    • 序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时把使用的数据传递过来。

    • 序列化器的字段声明类似于我们前面使用过的表单系统。

    • 开发restful api时,序列化器会帮我们把模型数据转换成字典.

    • drf提供的视图会帮我们把字典转换成json,或者把客户端发送过来的数据转换字典.

序列化器的使用

  • 序列化器的使用分两个阶段:

    • 处理客户端请求时,使用序列化器可以完成对数据的反序列化。

    • 处理服务器响应时,使用序列化器可以完成对数据的序列化。

#### 序列化

*

  ##### 基本序列化

  * 先查询出一个学生对象

    ```python
    from sers.models import Book
    book = Book.objects.get(pk=1)
    ```

  * 构造序列化器对象

    ```python
    from .serializers import BookSerializer
    bookSer = BookSerializer(instance=book)
    ```

  * 获取序列化数据,通过data属性可以获取序列化后的数据
  * 路由

    ```python
    # urls.py
    path("sers/", include("sers.urls")),
    # sers.urls
    path('books/(\d+)', BookView.as_view()),
    ```

  * 视图

    ```python
    from rest_framework.response import Response
    from rest_framework.views import APIView
    from .models import Book
    from .sers import BookSerializer

    class BookView(APIView):

        def get(self, request,id):
            book = Book.objects.get(pk=id)
            bs = BookSerializer(instance=book)
            return Response(bs.data)
    ```

  * 如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加**many=True** 参数补充说明

    ```python
    class BookView(APIView):

        def get(self, request):
            # book = Book.objects.get(pk=1)
            books = Book.objects.all()
            bs = BookSerializer(instance=books, many=True)
            return Response(bs.data)
    ```

反序列化

##### 数据验证

* 使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。

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

  验证失败,可以通过序列化器对象的**errors** 属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的**NON_FIELD_ERRORS_KEY**来控制错误字典中的键名。

  验证成功,可以通过序列化器对象的**validated_data**属性获取数据。

  在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。

  通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证。

  ```python
  from sers.sers import BookSerializer
  bs = BookSerializer(data={"title":"小王子","price":100})
  bs.is_valid()  # 必须先要is_valid,才会有bs.validated_data和bs.errors
  False
  bs.validated_data
  {}
  bs.errors
  {'pub_date': [ErrorDetail(string='This field is required.', code='required')]}
  ```

  is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递**raise_exception=True**参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
*

  ###### validate_字段名,对`<field_name>`字段进行验证,如

  ```python
  class BookSerializer(serializers.Serializer):
      title = serializers.CharField(max_length=32)
      price = serializers.IntegerField(required=True)
      pub_date = serializers.DateField(required=True)

      def validate_title(self, value):
          if 'django' not in value.lower():
              raise serializers.ValidationError("图书不是关于Django的")
          return value
  ```

* 测试

  ```python
  from sers.sers import BookSerializer
  bs = BookSerializer(data={"title":"小王子","price":100})
  bs.is_valid()
  False
  bs.errors
  {'title': [ErrorDetail(string='图书不是关于Django的', code='invalid')], 'pub_date': [ErrorDetail(string='This field is required.', code='required')]}
  ```

*

  ###### validate,在序列化器中需要同时对多个字段进行比较验证时,可以定义validate方法来验证,如

  ```python

  class BookSerializer(serializers.Serializer):
      title = serializers.CharField(max_length=32)
      price = serializers.IntegerField(required=False)
      pub_date = serializers.DateField(required=False)

      bread = serializers.IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False)
      bcomment = serializers.IntegerField(label='评论量', max_value=2147483647, min_value=-2147483648, required=False)


      def validate_title(self, value):
          if 'django' not in value.lower():
              raise serializers.ValidationError("图书不是关于Django的")
          return value

      def validate(self, data):
          bread = data.get("bread")
          bcomment = data.get("bcomment")
          if bread < bcomment:
              raise serializers.ValidationError('阅读量小于评论量')
          return data
  ```

*

  ##### 反序列化-保存数据,

  前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.

  可以通过实现create()和update()两个方法来实现。
  在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了,book = serializer.save()
#### 基于APIView的接口实现

* 路由

  ```python
  urlpatterns = [
      path('book/', views.BookView.as_view()),
      re_path('book/(\d+)', views.BookDetailView.as_view()),
  ]
  ```

* 视图

  ```python
  # Create your views here.
  from rest_framework.views import APIView

  # 设计增删改查查接口


  # 视图
  class BookView(APIView):

      def get(self, request):
          books = Book.objects.all()
          bs = BookSerializer(instance=books, many=True)
          return Response(bs.data)

      def post(self, request):
          bs = BookSerializer(data=request.data)
          if bs.is_valid():
              bs.save()
              return Response(bs.data)
          else:
              return Response(bs.errors)


  class BookDetailView(APIView):

      def get(self, request, pk):
          book = Book.objects.get(pk=pk)
          bs = BookSerializer(instance=book)
          return Response(bs.data)

      def put(self, request, pk):
          instance = Book.objects.get(pk=pk)
          bs = BookSerializer(instance=instance, data=request.data)
          if bs.is_valid():
              bs.save()
              return Response(bs.data)
          else:
              return Response(bs.errors)

      def delete(self, request, pk):
          Book.objects.get(pk=pk).delete()
          return Response()
  ```

* serializer

  ```python
  # 序列化器
  from rest_framework import serializers
  from rest_framework.response import Response
  from .models import Book


  class BookSerializer(serializers.Serializer):
      title = serializers.CharField()
      price = serializers.IntegerField()
      pub_date = serializers.DateField()

      def create(self, validated_data):
          new_book = Book.objects.create(**validated_data)

          return new_book

      def update(self, instance, validated_data):
          Book.objects.filter(pk=instance.pk).update(**validated_data)
          instance = Book.objects.get(pk=instance.pk)

          return instance

  ```
相关推荐
浊酒南街2 小时前
决策树python实现代码1
python·算法·决策树
FreedomLeo13 小时前
Python机器学习笔记(十三、k均值聚类)
python·机器学习·kmeans·聚类
星光樱梦3 小时前
32. 线程、进程与协程
python
阿正的梦工坊3 小时前
深入理解 PyTorch 的 view() 函数:以多头注意力机制(Multi-Head Attention)为例 (中英双语)
人工智能·pytorch·python
西猫雷婶4 小时前
python学opencv|读取图像(十九)使用cv2.rectangle()绘制矩形
开发语言·python·opencv
海绵波波1074 小时前
flask后端开发(10):问答平台项目结构搭建
后端·python·flask
赵谨言5 小时前
基于python网络爬虫的搜索引擎设计
爬虫·python·搜索引擎
code04号5 小时前
python脚本:批量提取excel数据
开发语言·python·excel
hakesashou5 小时前
python如何打乱list
开发语言·python
网络风云5 小时前
【魅力golang】之-反射
开发语言·后端·golang