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 小时前
项目实战--Spring Boot + Minio文件切片上传下载
java·spring boot·后端
码农爱java2 小时前
Spring Boot 中的监视器是什么?有什么作用?
java·spring boot·后端·面试·monitor·监视器
Apifox.3 小时前
什么是 HTTP POST 请求?初学者指南与示范
后端·http·学习方法·web
2401_858120264 小时前
探索sklearn文本向量化:从词袋到深度学习的转变
开发语言·python·机器学习
无名指的等待7124 小时前
SpringBoot实现图片添加水印(完整)
java·spring boot·后端
bigbearxyz5 小时前
Java实现图片的垂直方向拼接
java·windows·python
立秋67895 小时前
使用Python绘制堆积柱形图
开发语言·python
jOkerSdl6 小时前
第三十章 方法大全(Python)
python
小白学大数据6 小时前
HTML内容爬取:使用Objective-C进行网页数据提取
大数据·爬虫·python·html·objective-c·cocoa
逆境清醒7 小时前
开源数据科学平台Anaconda简介
人工智能·python·深度学习·机器学习·anaconda