Django-drf框架之序列化器超详解

前言

这几年一直在it行业里摸爬滚打,一路走来,不少总结了一些python行业里的高频面试,看到大部分初入行的新鲜血液,还在为各样的面试题答案或收录有各种困难问题

于是乎,我自己开发了一款面试宝典,希望能帮到大家,也希望有更多的Python新人真正加入从事到这个行业里,让python火不只是停留在广告上。

微信小程序搜索:Python面试宝典

或可关注原创个人博客:https://lienze.tech

也可关注微信公众号,不定时发送各类有趣猎奇的技术文章:Python编程学习

序列化器

普通序列化器

Response是不能直接返回ORM数据的,所以需要我们进行序列化操作,可以通过手动将其转为字典或JSON***,也可以使用DRF所提供的序列化器,我们一般建议您使用序列化器*,这个更专业,更简单,并且格式更为统一

如果你经常使用的是自己去将数据封装为***JSON***,那么常见的代码模型就像这样

data = models.objects.all()
json_ = {}
for d in data:
    json_['age'] = d.age
    json_['name'] = d.name
return Response(json_)

字段多了的话,这个工作量就会越来越麻烦了,而且有关于时间(DateTimeField、DateField)等字段类型的序列化直接通过***JSON***也是不行的,需要自己手动编写**JSON的序列化器,非常麻烦,于是乎 DRF 就提供了更为便捷的两种序列化器,普通序列化器模型序列化器

普通序列化器编写方式
from rest_framework import serializers

普通序列化器,可以按照给定字段,将所匹配的ORM数据字段转换为***JSON***数据,不光可以对一条数据,也可以对一个**QuerySet所对应的结果集


比如一个课程表有如下一些字段

class Course(models.Model):
    name = models.CharField(max_length=20, verbose_name='课程名字')
    created = models.DateField(verbose_name='课程创建时间')
    def __str__(self):
        return self.name

测试数据可以通过数据库手动添加
那么普通序列化器就可以定义如下,按照模型类字段支持即可,非常简单

class CourseSer(serializers.Serializer):
    name = serializers.CharField(max_length=20)
    created = serializers.DateField(auto_now_add=True)

普通的序列化器,不光可以为数据库模型类定义,也可以为非数据库模型类的数据定义,只是这里为模型类定义时,需要根据模型类字段一一映射

普通序列化器序列化

序列化就是将ORM数据放入序列化器加工,诞生出***JSON***数据对象,序列化器对象的 data 属性即为处理好的 JSON 数据对象

  • 单条数据的序列化

单挑数据的序列化很简单,直接通过序列化器类对象的参数***instance***传入查询得到的结果即可

object = models.objects.get(pk=1)
ser_data = Serializer(instance=object)
ser.data # 这就是这一条数据的 JSON 结果
  • 多条数据的序列化

如果使用像***filter***、all这样的一些ORM方法,获取到的是QuerySet结果集,不是单独数据对象,那么使用序列化器时,需要传入many=True参数,用来表示:哇哦~,好多数据呢

objects = models.objects.all()
ser_data = Serializer(instance=objects, many=True)
ser_data.data # 这就是这一群数据的 JSON 结果
普通序列化器反序列化创建

反序列化的概念很简单,就是把JSON等数据变为ORM数据对象,甚至是入库或者是修改**

DRF要求序列化器必须对数据进行校验,才能获取验证成功的数据或保存成模型类对象


  1. 在操作过程中,反序列化首先需要通过data传参
  2. 接着调用is_valid进行校验,验证成功返回True,反之返回False**
    1. 如果校验失败,还可以通过结果的errors属性返回错误值
    2. ***is_valid*调用后方法会进行字段属性(max_value=10)**的校验、自定义的校验等等
  3. 对校验过后的对象调用***save***方法,这个**save方法会触发序列化器中的***create***方法
    1. 普通序列化器中,***create***方法默认是没有实现的,需要手动根据模型类进行编写

data = {
    'name':"张三",
    ...
}
ser = Serializer(data=data)
if ser.is_valid():
    ser.save() # 只传 data 参数的时候,save 方法会触发序列化器器中的 create 方法

比如现在,还是之前练习需要提交数据创建课程的接口,此时可以这么做

为了能够保证数据成功入库,默认的普通序列化器是不具备入库功能的,需要编写***create***方法

class CourseSer(serializers.Serializer):
    name = serializers.CharField(max_length=20)
    created = serializers.DateField()
    def create(self, validated_data):
        object = Course.objects.create(
            **validated_data
        )
        return object

成功之后,就可以通过像之前一样的数据提交,编写视图完成数据入库,序列化器可以直接处理***request***所提交的数据***data***,并且可以剔除在**request.data中其他多余的字段,只会处理序列化器里的字段

class CourseCreate(APIView):
    def post(self, request):
        ser = CourseSer(data=request.data)
        if ser.is_valid():
            ser.save()
        error = ser.errors
        return Response({'msg': error if error else 'success'})
普通序列化器反序列化更新

反序列化经过校验的数据,不光可以创建数据,还可以更新数据

  1. 更新首先需要一个已经存在的数据,所以需要通过**instance参数传递已有的一个ORM对象
  2. 还需要待更新的新值,那么就需要传***data***参数
  3. 之后同样需要***is_valid***方法调用,检查即将更新进入的数据是否合法
  4. 最终***save***触发序列化器中的***update***方法

默认普通序列化器是没有自带对于数据的更新方法的,现在需要在序列化器里创建***update***方法

class CourseSer(serializers.Serializer):
    name = serializers.CharField(max_length=20)
    created = serializers.DateField()
    def update(self, instance, validated_data):
        # instance 要更新的数据,validated_data 是新数据
        instance.name = validated_data.get('name', instance.name)
        instance.type = validated_data.get('create', instance.type)
        instance.save()
        return instance

然后通过PUT传递要更新数据的ID,以及更新后的值,来为某条数据更新

class CourseUpdate(APIView):
    def put(self, request):
        id_ = request.data.get("id") # 获取当前更新数据的 ID
        try:
            course = Course.objects.get(pk=id_)
        except Course.DoesNotExist:
            return Response({'msg': '更新失败,不存在这条数据'})
        ser = CourseSer(instance=course, data=request.data)
        if ser.is_valid():
            ser.save()
        error = ser.errors
        return Response({'msg': error if error else 'success'})

模型序列化器

模型序列化器编写方式

之前的序列化器,很明显可以感觉到,如果模型类字段少了,还行,但是模型字段越来越多,那么开发者序列化器里所要复刻的字段也要越来越多,很麻烦奥

而且还得手动实现***update***和**create方法,而且光写了序列化器字段还不行,还得有字段属性

于是乎,有了现在的与模型类关联的序列化器,可以更加方便的进行字段映射以及内置方法的编写,简直是太棒了


模型类关联序列化器大概总结有如下三个特性,一个缺点

  • 特点
    • 基于模型类自动生成一系列字段
    • 自动生成的系列字段,同时还包含***unique***、***max_length***等属性校验
    • 包含默认的***create***和***update***的实现
  • 缺点
    • 不会自动映射模型类字段的default属性

那么模型类关联序列化器用啥呢?用的是新的序列化器基

from rest_framework.serializers import ModelSerializer

比如一个商品模型类

class Goods(models.Model):
    title = models.CharField(max_length=200, verbose_name='商品标题')
    description = models.TextField(verbose_name='描述')
    inventory = models.IntegerField(default=0, verbose_name='库存量')
    price = models.DecimalField(
        max_digits=10, decimal_places=2, verbose_name='商品价格')
    cover = models.CharField(max_length=200, verbose_name='封面图')
    issale = models.BooleanField(default=False, verbose_name='是否促销')
    saleprice = models.DecimalField(
        max_digits=10, decimal_places=2, verbose_name='促销价格')
    ishow = models.BooleanField(default=True,verbose_name='是否上架')
    createtime = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    def __str__(self):
        return self.title
    class Meta:
        db_table = 'goods'

按照之前的普通序列化写法,你需要同步一个字段,并将字段属性也要记得同步,非常麻烦
但通过与模型类关联的序列化器就很简单了

  1. 首先通过继承***ModelSerializer***基类
  2. 通过序列化器元类属性中的**model属性关联模型类
  3. 通过序列化器元类属性中的fields属性指明序列化器需要处理的字段**
class GoodsSer(serializers.ModelSerializer):
    class Meta:
        model = Goods
        fields = '__all__' # 指明所有模型类字段
        # exclude = ('createtime',) # 排除掉的字段
        # read_only_fields = ('title','description') # 只用于序列化的字段
        # fields = ('title','description','inventory') # 手动指明字段
        # extra_kwargs = {
        #     'price':{'min_value':0, 'required':True},
        # } # 修改原有字段的选项参数

模型类关联的序列化器和普通的序列化器使用方法一样

使用序列化器返回当前所有的商品数据,还是像之前一样传入**instance参数即可,还要记得由于是多个商品,不是单独数据,要记得加many=True参数

模型序列化器反序列化创建、更新

模型序列化器的创建就更简单了,不需要手动实现***create***方法,大致流程如下:

  1. 为序列化器绑定数据ser=Serializer(data=request.data)
  2. 校验数据,ser.is_valid()
  3. 存储入库,ser.save()

创建商品接口

class GoodsCreate(APIView):
    def post(self, request):
        ser = GoodsSer(data=request.data)
        if ser.is_valid():
            ser.save()
        error = ser.errors
        return Response({'msg': error if error else 'success'})

注意:反序列化自动生成的字段属性中,不会包含原始模型类字段中的***default***字段属性

更新某一个商品数据,模型序列化器也是自带了***update***方法

更细商品接口

class GoodsUpdate(APIView):
    def put(self, request):
        id_ = request.data.get("id")
        try:
            goods = Goods.objects.get(pk=id_)
        except Goods.DoesNotExist:
            return Response({'msg': '更新失败,不存在这条数据'})

        ser = GoodsSer(instance=goods, data=request.data)
        if ser.is_valid():
            ser.save()
        error = ser.errors
        return Response({'msg': error if error else 'success'})
模型序列化器与普通序列化器的对比
  • 序列化时,将模型类对象传入***instance***参数
    • 序列化结果使用序列化器对象的data属性获取得到
  • 反序列化创建时,将要被反序列化的数据传入data参数
    • 反序列化一定要记得先使用***is_valid***校验
  • 反序列化更新时,将要更新的数据对象传入**instance参数,更新后的数据传入data参数
  • 模型序列化器普通序列化器更加方便,自动生成序列化映射字段,***create***方法等
  • 关联外键序列化,字段属性外键为时要记得加***many=True***

你可能感兴趣的:(Python学习,Django,django,python,后端)