Django REST framework序列化器详解:普通序列化器与模型序列化器的选择与运用

系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 一、普通序列化器-Serializer
    • [1. 普通序列化器编写方式](#1. 普通序列化器编写方式)
    • [2. 普通序列化器序列化](#2. 普通序列化器序列化)
    • [3. 普通序列化器反序列化创建](#3. 普通序列化器反序列化创建)
    • [4. 普通序列化器反序列化更新](#4. 普通序列化器反序列化更新)
    • [5. 普通序列化器完整代码](#5. 普通序列化器完整代码)
  • 二、模型序列化器-ModelSerializer
    • [1. 模型序列化器编写方式](#1. 模型序列化器编写方式)
    • [2. 模型序列化器反序列化创建、更新](#2. 模型序列化器反序列化创建、更新)
    • [3. 模型序列化器与普通序列化器的对比](#3. 模型序列化器与普通序列化器的对比)

前言

    在 Django REST framework 中,数据序列化至关重要。本文将探讨 普通序列化器模型序列化器,了解它们的基本功能和差异,帮助您根据项目需求选择合适的序列化器。


Response 是不能直接返回ORM 数据的,所以需要我们进行序列化 操作,可以通过手动将其转为字典或JSON ,也可以使用DRF 所提供的序列化器,一般建议使用序列化器

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

python 复制代码
data = models.objects.all()
json_data = {}
for d in data:
    json_data['age'] = d.age
    json_data['name'] = d.name
return Response(json_data)

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


一、普通序列化器-Serializer

1. 普通序列化器编写方式

导包:from rest_framework import serializers

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


例如:

用户表 UserModel:

python 复制代码
#models.py
from django.db import models

# Create your models here.
class UserModel(models.Model):
    name = models.CharField(max_length=50)
    phone = models.CharField(max_length=11)
    password = models.CharField(max_length=30)
    info = models.CharField(max_length=100, null=True)

    def __str__(self):
        return self.name
    class Meta:
        db_table = 'user'

普通序列化器UserSerializer定义如下:

python 复制代码
#userSerializer.py
class UserSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=50)
    phone = serializers.CharField(validators=[validators_phone])
    password = serializers.CharField(max_length=30)
    info = serializers.CharField(max_length=100,default="默认值")

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

1、在客户端请求时,使用序列化器可以完成对数据的反序列化(将字典格式的数据转化为模型对象)。

2、在服务器响应时,使用序列化器可以完成对数据的序列化(将模型对象转化为字典格式的数据)。


2. 普通序列化器序列化

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

1、单条数据的序列化:

  • 单挑数据的序列化 很简单,直接通过序列化器类 对象的参数instance传入查询得到的结果即可
python 复制代码
#views.py
class UserIdView(APIView):
    def get(self, request, id):
        user = UserModel.objects.get(pk=id)
        usSer = UserSerializer(instance=user)

        return Response({"message": "get测试成功!", "data": usSer.data})

2、多条数据的序列化:

  • 如果使用像filterall 这样的一些ORM 方法,获取到的是QuerySet 结果集,不是单独数据对象,那么使用序列化器 时,需要传入many=True参数,用来表示:传入的不止一条数据。
python 复制代码
#views.py
class UserView(APIView):

    def get(self, request):
        users = UserModel.objects.all()
        usSer = UserSerializer(instance=users, many=True)
        return Response({"message":"get测试成功!","data":usSer.data})

Serializer属性中选项参数

选项参数名称 作用
max_length 最大长度
min_length 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
max_value 最大值
min_value 最小值
通用参数名称 作用
read_only 该字段仅用于序列化输出,需要序列化输出时设置:read_only=True;默认为False
write_only 该字段仅用于反序列输入,需要序列化输入时设置:write_only=True;默认为False
required 该字段表示在反序列化输入时必须输入
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
validators 对字段进行校验,定义在字段中
error_message 当字段校验不通过时,报error_message的value值
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息

3. 普通序列化器反序列化创建

反序列化 的概念很简单,就是把JSON等数据变为ORM数据对象,甚至是入库 或者是修改
DRF 要求序列化器必须对数据进行校验,才能获取验证成功的数据 或保存成模型类对象


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

def validators_phone(values):
    r_phone = r"^1[3-9]\d{9}$"
    if re.match(r_phone, values):
        print("手机号匹配成功!")
    else:
        print("手机号匹配失败,抛出异常!")
        raise serializers.ValidationError("手机号匹配失败!不满足规则!")


class UserSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=50)
    phone = serializers.CharField(validators=[validators_phone])
    password = serializers.CharField(max_length=30)
    info = serializers.CharField(max_length=100,default="默认值")

比如现在,需要提交数据用到创建User 的接口,此时可以这么做

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

python 复制代码
#userSerializer.py
class UserSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=50)
    phone = serializers.CharField(validators=[validators_phone])
    password = serializers.CharField(max_length=30)
    info = serializers.CharField(max_length=100,default="默认值")

    def create(self, validated_data):
        object = UserModel.objects.create(**validated_data)
        return object
        
#具体来说,**validated_data的作用是:解包字典。
#它将validated_data字典中的键值对解包为一系列的关键字参数。

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

python 复制代码
# views.py
class UserView(APIView):

    def post(self, request):
        ser = UserSerializer(data=request.data) # 传参data,进行反序列化
        if ser.is_valid():
            print("校验成功!")
            ser.save()
            return Response({"message":"[POST]信息添加成功!"})
        else:
            print("校验失败!")
            return Response({"message": ser.errors})

4. 普通序列化器反序列化更新

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

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

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

python 复制代码
# userSerializer.py
class UserSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=50)
    phone = serializers.CharField(validators=[validators_phone])
    password = serializers.CharField(max_length=30)
    info = serializers.CharField(max_length=100,default="默认值")

    def update(self, instance, validated_data):
        # instance 要更新的数据,validated_data 是新数据
        instance.name = validated_data.get('name', instance.name)
        instance.phone = validated_data.get('phone', instance.phone)
        instance.password = validated_data.get('password', instance.password)
        instance.info = validated_data.get('info', instance.info)
        instance.save()
        return instance

#获取字段值:
#validated_data.get('name') 尝试从 validated_data 字典中获取键为 'name' 的值。
#validated_data 是由序列化器在验证请求数据后生成的一个字典,它包含了经过验证的字段和它们的值。

#默认值机制:
#get 方法有一个可选的第二个参数,即默认值。如果 'name' 这个键不存在于validated_data 中,get 方法将返回这个默认值。
#在这个例子中,如果请求数据中没有包含 'name' 字段,那么默认值就是 instance.name,即当前模型实例的 name 字段的值。

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

python 复制代码
class UserIdView(APIView):
    def put(self, request, id):
        user = UserModel.objects.get(pk=id)
        ser = UserSerializer(instance=user, data=request.data)
        if ser.is_valid():
            print("校验成功!")
            ser.save()
            return Response({"message": "[PUT]信息修改成功!"})
        else:
            print("校验失败!")
            return Response({"message": ser.errors})

5. 普通序列化器完整代码

models.py

python 复制代码
from django.db import models

# Create your models here.
class UserModel(models.Model):
    name = models.CharField(max_length=50)
    phone = models.CharField(max_length=11)
    password = models.CharField(max_length=30)
    info = models.CharField(max_length=100, null=True)

    def __str__(self):
        return self.name
    class Meta:
        db_table = 'user'

userSerializer.py

python 复制代码
from rest_framework import serializers
from app.models import UserModel
import re

def validators_phone(values):
    r_phone = r"^1[3-9]\d{9}$"
    if re.match(r_phone, values):
        print("手机号匹配成功!")
    else:
        print("手机号匹配失败,抛出异常!")
        raise serializers.ValidationError("手机号匹配失败!不满足规则!")


class UserSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=50)
    phone = serializers.CharField(validators=[validators_phone])
    password = serializers.CharField(max_length=30)
    info = serializers.CharField(max_length=100,default="默认值")

    def create(self, validated_data):
        object = UserModel.objects.create(**validated_data)
        return object

    def update(self, instance, validated_data):
        # instance 要更新的数据,validated_data 是新数据
        instance.name = validated_data.get('name', instance.name)
        instance.phone = validated_data.get('phone', instance.phone)
        instance.password = validated_data.get('password', instance.password)
        instance.info = validated_data.get('info', instance.info)
        instance.save()
        return instance

views.py

python 复制代码
from rest_framework.views import APIView
from rest_framework.response import Response
from app.models import UserModel
from app.serializer.userSerializer import UserSerializer
from django.shortcuts import render

# Create your views here.


class UserView(APIView):

    def get(self, request):
        users = UserModel.objects.all()
        usSer = UserSerializer(instance=users, many=True)
        return Response({"message":"get测试成功!","data":usSer.data})

    def post(self, request):
        ser = UserSerializer(data=request.data) # 传参data,进行反序列化
        if ser.is_valid():
            print("校验成功!")
            ser.save()
            return Response({"message":"[POST]信息添加成功!"})
        else:
            print("校验失败!")
            return Response({"message": ser.errors})

class UserIdView(APIView):
    def get(self, request, id):
        user = UserModel.objects.get(pk=id)
        usSer = UserSerializer(instance=user)

        return Response({"message": "get测试成功!", "data": usSer.data})

    def put(self, request, id):
        user = UserModel.objects.get(pk=id)
        ser = UserSerializer(instance=user, data=request.data)
        if ser.is_valid():
            print("校验成功!")
            ser.save()
            return Response({"message": "[PUT]信息修改成功!"})
        else:
            print("校验失败!")
            return Response({"message": ser.errors})

urls.py

python 复制代码
from django.urls import path
from app.views import UserView,UserIdView

urlpatterns = [
    path('user/', UserView.as_view()),
    path('user/<int:id>/', UserIdView.as_view()),
]

二、模型序列化器-ModelSerializer

1. 模型序列化器编写方式

之前的普通序列化器 ,很明显可以感觉到,如果模型类字段少了,还行,但是模型字段越来越多,那么开发者序列化器 里所要复刻的字段也要越来越多,很麻烦, 而且还得手动实现updatecreate方法,而且光写了序列化器字段 还不行,还得有字段属性

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


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

  • 特点:
    • 基于模型类自动生成一系列字段
    • 自动生成的系列字段,同时还包含uniquemax_length等属性校验
    • 包含默认的createupdate的实现
  • 缺点:
    • 不会自动映射模型类字段的default属性

模型类关联序列化器 用的是新的序列化器基类

python 复制代码
from rest_framework.serializers import ModelSerializer

用户模型类依旧使用上文中的UserModel.py文件
按照之前的普通序列化写法,你需要同步一个字段,并将字段属性也要记得同步,非常麻烦,但通过与模型类关联的序列化器就很简单了。

  1. 首先通过继承ModelSerializer基类
  2. 通过序列化器元类属性中的model属性关联模型类
  3. 通过序列化器元类属性中的fields属性指明序列化器 需要处理的字段
python 复制代码
# userModelSerializer.py
from rest_framework import serializers
from app.models import UserModel

class UserModelSerializer(serializers.ModelSerializer):
    # 不需要再重写 create 和 update 方法了,可查看ModelSerializer源码
    class Meta:
        model = UserModel
        fields = '__all__' # 指明所有模型类字段

        # exclude = ('password',) # 排除掉的字段
        # read_only_fields = ('name','info') # 只用于序列化的字段
        # fields = ('name','phone','password','info')
        # extra_kwargs = {
        #     'info':{'min_length':5, 'required':True},
        # } #修改原有字段的选项参数

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

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

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

  1. 为序列化器绑定数据ser=Serializer(data=request.data)
  2. 校验数据,ser.is_valid()
  3. 存储入库,ser.save()
    创建用户接口:
python 复制代码
from rest_framework.views import APIView
from rest_framework.response import Response
from app.models import UserModel
from app.serializer.userModelSerializer import UserModelSerializer

# Create your views here.

class UserView(APIView):

    def get(self, request):
        users = UserModel.objects.all()
        usSer = UserModelSerializer(instance=users, many=True)
        return Response({"message":"get测试成功!","data":usSer.data})

    def post(self, request):
        ser = UserModelSerializer(data=request.data) # 传参data,进行反序列化
        if ser.is_valid():
            print("校验成功!")
            ser.save()
            return Response({"message":"[POST]信息添加成功!"})
        else:
            print("校验失败!")
            return Response({"message": ser.errors})

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


更细用户信息接口:

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

python 复制代码
class UserIdView(APIView):
    def get(self, request, id):
        user = UserModel.objects.get(pk=id)
        usSer = UserModelSerializer(instance=user)

        return Response({"message": "get测试成功!", "data": usSer.data})

    def put(self, request, id):
        user = UserModel.objects.get(pk=id)
        ser = UserModelSerializer(instance=user, data=request.data)
        if ser.is_valid():
            print("校验成功!")
            ser.save()
            return Response({"message": "[PUT]信息修改成功!"})
        else:
            print("校验失败!")
            return Response({"message": ser.errors})

3. 模型序列化器与普通序列化器的对比

  • 序列化时 ,将模型类对象传入instance参数
    • 序列化结果使用序列化器对象的data属性获取得到
  • 反序列化创建时 ,将要被反序列化 的数据传入data参数
    • 反序列化一定要记得先使用is_valid校验
  • 反序列化更新 时,将要更新的数据对象传入instance参数,更新后的数据传入data参数
  • 模型序列化器普通序列化器 更加方便 ,自动生成序列化映射字段,createupdate方法等
  • 关联外键序列化 ,字段属性外键为 时要记得加many=True

相关推荐
叠层归一研究院1 天前
如何用程序搭建一个 AGI 种子系统(一):从向量种子到无限生长引擎
人工智能·python·算法·机器学习·agi
水深火乐1 天前
安全地生成验证码、密码和 Token
后端
小强19881 天前
SQL Server 慢查询怎么定位?一套从“卡”到“快”的完整排查流程
后端
水深火乐1 天前
interface和any
后端
步行cgn1 天前
MyBatis Error evaluating expression ‘ids‘. Return value (3) was not iterable 错误详
java·后端
神奇小汤圆1 天前
Spring Boot + LangChain4j实现RAG——从零搭建企业级知识库问答系统
后端
H_Peak1 天前
Python运算符与流程控制:if条件判断
后端
H_Peak1 天前
Python字符串操作:从基础到正则入门
后端
自进化Agent智能体1 天前
Hermes 子代理委派 —— 并行工作的艺术
后端
步行cgn1 天前
MyBatis 动态 SQL 中的 <foreach> 标签完全解析
后端