Drf序列化组件 | Serializer | 模型类序列化器ModelSerializer具体使用

DRF序列化组件

# 作用:
1. 序列化,序列化器(类)会把模型对象(Book对象,Queryset对象)转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发送过来的数据,经过request以后变成字典(request.data),序列化器(类)可以把字典转成模型
3. 反序列化,完成数据校验功能

# 本质:
    就是写一个类继承一个类
    可以完成序列化,反序列化和数据校验

序列化之Serializer类的具体使用

准备:

# 因为他的目的就是序列化与反序列化,所以建议把它建立在一个单独的py文件下。
# 这里新建使用   serializer.py(见明知意)

具体使用:

models.py创建一个模型表

from django.db import models

class BOOKS(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()
    publish = models.CharField(max_length=32)

serializer.py序列化类

from rest_framework import serializers

# 创建序列化类继承Serializer,目的:序列化和反序列化Book表
class BookSerializer(serializers.Serializer):
    # 对应字段(要序列化,反序列化的字段)
    name = serializers.CharField(这里可以写校验数据校验规则(相当于forms组件))
    price = serializers.IntegerField()
    publish = serializers.CharField()

urls.py

urlpatterns = [
    path('books/',views.BookAPIView.as_view()),
]

# 通过books/路由访问BookAPIView视图类

views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
from .serializer import BookSerializer   # 导入序列化类来使用

# 查询多个数据接口
class BookAPIView(APIView):
    # 查询数据是get请求的结果
    def get(self,request,*args,**kwargs):
        # 查询book表中所有字段数据
        book_list = models.BOOKS.objects.all()
        # 序列化过程,把queryset转换成字典
        # 第一个参数是需要序列化的对象,如果序列化多条数据,一定要加上many=True
        ser = BookSerializer(instance=book_list,many=True)  # 可使用关键字传参
        # ser = BookSerializer(book_list,many=True)  # 可使用位置传参
        # 将数据返回(此时数据是字典形式,返回到前端则是json格式数据,这是Response帮我们完成的,serializer序列化是将queryset对象转换为字典的形式。)
        return Response(ser.data)

操作单条数据:

需重写路由:

urlpatterns = [
    path('books/',views.BookAPIView.as_view()),
    # 操作单个数据(使用转换器传入pk值操作单条数据)
    path('books/<int:pk>',views.BookDetailAPIView.as_view())
]
# 查询单个:
class BookDetailAPIView(APIView):
    def get(self,request,pk):
        book = models.BOOKS.objects.filter(pk=pk).first()
        # 序列化单个数据就不需要添加many=True参数
        ser = BookSerializer(book)
        return Response(ser.data)
    
# 删除单个:
# 发送delete请求
class BookDetailAPIView(APIView):
    def delete(self,request,pk):
        # 删除数据无需序列化与反序列化直接删除即可
        models.BOOKS.objects.filter(pk=pk).delete()
        # 删除成功返回一个空,如果没删除成功会自己抛异常返回一个空
        return Response()
    
    
# 修改单个:
# 发送put请求
class BookDetailAPIView(APIView):
    def put(self,request,pk):
        book = models.BOOKS.objects.filter(pk=pk).first()
        # 修改数据是我们自己写json格式数据,然后传给后端,所以需要反序列化
        # 第一个参数填写需要修改的值,第二个参数(data)填写用户上传的新的值
        ser = BookSerializer(instance=book,data=request.data)
        # 校验数据
        if ser.is_valid():
            ser.save()
            return Response(ser.data)

新增单个:

class BookAPIView(APIView):
    def post(self,request,*args,**kwargs):
        ser = BookSerializer(data=request.data)  # 如果要新增就不需要传instance
        if ser.is_valid():
            ser.save()
            return Response(ser.data)

特别注意:

修改和新增需要重写create与updata方法

 # 在编写新增与修改功能的时需要在serializer的类中重写create()与updata()方法
 # 不然会报错:因为不重写不知道保存在那张表中。


    def update(self, instance, validated_data):
        # instance就是book对象 validated_data校验通过的数据
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        # 保存(book对象所有的save方法)
        # 通过表对象保存,这样就知道了保存到那张表中
        instance.save()
        # 返回
        return instance

    def create(self, validated_data):
        # validated_data为用户上传的数据
        book = models.BOOKS.objects.create(**validated_data)  # 打散保存
        # 通过表对象保存,这样就知道了保存到那张表中
        # 返回
        return book

source

引子:

# 那么如果想要使用别的字段名,那么这里就需要使用到source
# source的作用:可以对应表模型的字段和方法(返回结果是什么,字段就是什么)

source基本使用:

class BookSerializer(serializers.Serializer):
    # source参数编写对应表模型的字段名(想与那个字段做对应)
    book_name = serializers.CharField(source='name')

# source也可以对应表模型中的方法(方法的返回结果是什么,字段对应的结果就是什么)
class BOOKS(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()
    publish = models.CharField(max_length=32)

    def get_book_name(self):
        return '经典名著'+self.name

class BookSerializer(serializers.Serializer):
    # source编写方法名,返回方法的返回结果
    book_name = serializers.CharField(source='get_book_name')

# 放法2:不使用source方法
class BookSerializer(serializers.Serializer):
    get_book_name = serializers.CharField()

使用场景:

urls.py

path('books/',views.BookAPIView.as_view()),

models.py

class BOOKS(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()
    publish = models.ForeignKey(to='Publish',on_delete=models.DO_NOTHING)


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)

serializer.py

from rest_framework import serializers
from app01 import models
class BookSerializer(serializers.Serializer):
    # 写字段(要序列化,反序列化的字段)
    name = serializers.CharField()
    price = serializers.IntegerField()
    publish = serializers.CharField()

views.py

from rest_framework.response import Response
from app01 import models
from .serializer import BookSerializer
class BookAPIView(APIView):
    def get(self,request,*args,**kwargs):
        # 查询book表中所有字段的对应关系
        book_list = models.BOOKS.objects.all()
        # 序列化过程,把queryset转换成字典
        # 第一个参数是需要序列化的对象,如果序列化多条数据,一定要加上many=True
        ser = BookSerializer(book_list,many=True)
        # 将数据返回
        print(ser.data)
        return Response(ser.data)

运行结果:

# 那么我们如何拿到关联表所有字段的值(拿到出版社的详细信息)呢?
# 方式一:我们也可以使用上述的方法
# 如下:我们可以看到该方法非常的古怪,没有人会这样使用。

# 方式二:使用source方法实现

# 方式三:不使用source直接写对应方法名

# 方式四:使用SerializerMethodField()方法不需要在表模型中写方法,在序列化类中编写
# 使用使用SerializerMethodField就必须指定一个get_字段名的方法
# 如果字段名不一致则报错
# 该字段名是SerializerMethodField方法需要序列化的字段

source主要作用:就是用来做一对多,多对多的字段返回。

数据校验

# urls.py
path('publish/',views.PublishAPIView.as_view()),


# serializer.py
class PublishSerializer(serializers.Serializer):
    # 写字段(要序列化,反序列化的字段)
    name = serializers.CharField(max_length=8,min_length=3)  # 编写数据校验规范
    addr = serializers.CharField(max_length=8,min_length=3)
    
    # 重写新增功能
    def create(self, validated_data):
        # validated_data为用户上传的数据
        publish = models.Publish.objects.create(**validated_data)  # 打散保存
        # 返回
        return publish

    
# views.py
class PublishAPIView(APIView):
    def get(self,request,*args,**kwargs):
        # 查询book表中所有字段的对应关系
        publish_list = models.Publish.objects.all()
        # 序列化过程,把queryset转换成字典
        # 第一个参数是需要序列化的对象,如果序列化多条数据,一定要加上many=True
        ser = PublishSerializer(publish_list,many=True)
        # 将数据返回
        return Response(ser.data)

    def post(self,request,*args,**kwargs):
        ser = PublishSerializer(data=request.data)  # 如果要新增就不需要传instance
        # 校验数据是否通过
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response({'msg':'出错'})

局部钩子

    # 局部钩子
    def validate_name(self,name):
        if name.startswith('sb'):
            # 抛异常
            raise ValidationError("不能以sb开头")
        else:
            return name

全局钩子

    # 全局钩子
    def validate(self, attrs):   # attrs存放的就是request.data的数据
        name=attrs.get('name')
        addr=attrs.get('addr')
        return attrs

模型类序列化器

# 创建模型类序列化类需要继承 serializers.ModelSerializer
# 如果想要使用该序列化器记得修改views.py视图层函数
# create和update不需要重写,它帮我们封装好了

# 创建模型类序列化器
class PublishModelSerializer(serializers.ModelSerializer):
    class Meta:   # 这里就不需要写对应的字段,直接写对应的表即可
        model = models.Publish   # 对应Publish表
        
        fields = ['id','name']   # 序列化哪些字段 (只序列化id,name字段)
        
        fields = '__all__'       # 序列化全部字段
        
        fields = ['id','publish_detail']   # 也可序列化模型类中的方法
        
        exclude = ['id']         # 除了id字段其他都序列化(但不会存在方法)
        
# 创建模型类序列化器
class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.BOOKS
        fields = '__all__'
        depth = 1    # 深度:深一层(外键深入的意思) 非常耗费效率,不能控制深入后想要查询的字段,不建议使用,写多层不会报错,有几层就深入几层

参数总结:

fields = ['id','name']   # 序列化哪些字段 (只序列化id,name字段)
        
fields = '__all__'       # 序列化全部字段

fields = ['id','publish_detail']   # 也可序列化模型类中的方法

exclude = ['id']         # 除了id字段其他都序列化(但不会存在方法)

depth = 1    # 深度:深一层(外键深入的意思) 非常耗费效率,不能控制深入后想要查询的字段,不建议使用,写多层不会报错,有几层就深入几层

重写字段:

# 重写字段SerializerMethodField和初始序列化类使用方法一样

name = serializers.SerializerMethodField()
def get_name(self,obj):
    return '出版社:'+obj.name

添加字段:

# 添加字段和初始化序列化类使用方法一样
publish_detail = serializers.CharField(source='publish_detail')

字段校验映射:

# 自己的字段校验规则:映射了表模型的规则(如果校验失败则同样会添加到ser.errors错误信息中)

局部钩子与全局钩子:

# 与初始序列化类使用方法完全一致
    # 局部钩子
    def validate_name(self,name):
        if name.startswith('sb'):
            # 抛异常
            raise ValidationError("不能以sb开头")
        else:
            return name

    # 全局钩子
    def validate(self, attrs):   # attrs存放的就是request.data的数据
        name=attrs.get('name')
        addr=attrs.get('addr')
        return attrs

write_only()与read_only()方法

### write_only只写
反序列化时候使用,序列化的时候不用
### read_only只读
序列化的时候使用,反序列化的时候不用

 # 使用场景
    # 新增字段
    # 读的时候只读name_detail字段
    name_detail = serializers.SerializerMethodField(read_only=True)
    def get_name_detail(self,obj):
       return '新增'+obj.name
    # name字段只写,此时的name字段在__all__里(现在已经不能读了因为只限制可以写)
    name = serializers.CharField(write_only=True)

额外给字段添加参数:

# 上述这样如果有很多字段需要限制只读只写参数的话非常的麻烦
    # 需要编写在class META:类中
    # 额外给字段传递额外参数关键字:extra_kwargs
    extra_kwargs = {'name': {'write_only': True}}
    # 相当于:name = serializers.CharField(write_only=True)
posted @ 2022-04-22 23:42  JasonBorn  阅读(168)  评论(0编辑  收藏  举报