【DRF】序列化器ModelSerializer的使用

不使用序列化器的过程

1. 把前端发送请求过来的json字符串,通过json.loads转换成字典,字典转换为Python对象,存在数据库
2. 返回给前端数据,是把对象查询出来,转换成字典,再通过JsonResponse转换为json字符串

序列化器介绍

1. 序列化输出:序列化器把模型对象(qs)转换成字典,经过response变成json字符串给前端 `对象->字典->json`
2. 反序列化输入:把前端请求过来的数据,经过request以后变成字典(data),序列化器把字典转成模型存到数据库中,反序列化完成数据校验功能,前端传入的数据是否合法,长度校验等 `json->字典->对象`

Serializer序列化器使用方式

1.必须得继承Serializer类或者Serializer子类
2.定义的序列化器类中的字段名称“必须”与模型类中的字段名保持一致
3.默认定义哪些字段,那么哪些字段就会序列化输出,同时这些字段也必须输入(传递)
4.序列化器中定义的字段必须为Field子类
  CharField 字符串类型
  IntegerField  int类型
  BooleanField 布尔类型
  DataTimeField 日期类型
5.CharField可以指定max_length、min_length

通用参数

参数名称说明
label用于HTML展示API页面时,显示的字段名称
help_text用于HTML展示API页面时,显示的字段帮助提示信息
write_only=True,该字段前端必须输入,但不需要输出,请求完之后不会返回这个字段
read_only=True,该字段前端不需要输入,但是需要输出,请求完之后会返回这个字段
required=True, 指定该字段反序列化输入时,必须传递
allow_null=True 该字段可以传空值 null 不可以不传
allow_blank=True 可以传空字符串
default指定该字段的默认值,会将默认值做为反序列化的输入值

Serializer的使用

模型类

 class Book(models.Model):
     name = models.CharField(max_length=32)
     price = models.DecimalField(decimal_places=2, max_digits=5)
     author = models.CharField(max_length=32)

序列化类

from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.Serializer):
	name = serializers.CharField(max_length=8, min_length=3)
	price=serializers.CharField() # models中使用了DecimalField,这个位置使用了CharField会把小数类型转成字符串
    author = serializers.CharField()

视图类
序列化输出

class BookView(APIView):
   def get(self,request):
       """先从数据库查询出要所有数据"""
       book_list=Book.objects.all()
       """使用serializers里定义的序列化器对库里查出来的数据进行序列化,instance: 要序列化的对象,就是从库里查出来的数据
       many: 如果是查询集对象,many=True;如果是单个对象,many=False""" 
       ser=BookSerializer(instance=book_list,many=True)  # 传入初始化的参数instance=None, data=empty
       """将序列化后的数据返回给前端,serializer.data序列化后是字典"""
       return Response(ser.data) 

反序列化输入-新增
序列化类

from rest_framework import serializers
from .models import Book


class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8, min_length=3)
    price=serializers.CharField()
    author = serializers.CharField()
    price_info=serializers.CharField(read_only=True) 

    def create(self, validated_data):
        # validated_data校验过后的数据
        # 手动存到book表中
        book=Book.objects.create(**validated_data)
        # book=Book.objects.create(name=validated_data.get('name'))
        return book  # 不要忘记返回book对象

视图类

第一步:把前端传入的数据,放到Serializer对象中:ser=BookSerializer(data=request.data)
第二步:校验数据:ser.is_valid():
第三步:保存,ser.save()---》必须重写create,在序列化类中
     def create(self, validated_data):
        book=Book.objects.create(**validated_data)
        return book
class BookView(APIView):
    def post(self,request):
        """获取前端传过来的数据,字典格式传入data进行反序列化,创建序列化器对象"""
        ser=BookSerializer(data=request.data) 
        """校验前端传来的数据"""
        if ser.is_valid():  # 如果是true表示数据校验通过,通过,就保存
            # 如果instance为None,调用save本质会调用create--》父类create直接抛异常,所以我们要重写
            # 序列化器对象调用save方法时,会调用序列化器类中的create方法,进行数据创建操作
            ser.save()  #就会保存,重写create方法,如果不重写,我们不知道存到哪个表中,前提是使用的serializer,不是modelserializer
            return Response(ser.data)
        return Response({'code':101,'msg':'数据校验失败','err':ser.errors})

反序列化输入-修改
序列化类

class BookSerializer(serializers.Serializer):
    id = serializers.CharField(read_only=True)
    name = serializers.CharField(max_length=8, min_length=3)
    price = serializers.CharField(required=False) 
    author = serializers.CharField(required=False)

    def create(self, validated_data):
        # validated_data校验过后的数据
        # 手动存到book表中
        book = Book.objects.create(**validated_data)
        # book=Book.objects.create(name=validated_data.get('name'))
        return book  # 不要忘记返回book对象

    def update(self, instance, validated_data):
        # validated_data校验过后的数据,instance 是要修改的对象
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.author = validated_data.get('author')
        instance.save()  # 模型对象自带的save,保存到数据库中
        return instance  # 要忘记返回instance对象

视图类

 class BookDetailView(APIView):
     def get(self, request, pk):
         book = Book.objects.filter(pk=pk).first()
         ser = BookSerializer(instance=book)  # 如果是单条记录,many不传,就是false
         return Response(ser.data)

     def delete(self, request, pk):
         res = Book.objects.filter(pk=pk).delete()
         print(res)
         if res[0] > 0:
             return Response({'code': 100, 'msg': '删除成功'})
         else:
             return Response({'code': 103, 'msg': '数据不存在'})

     def put(self, request, pk):
         # 修改:用什么数据,修改哪个对象?
         book = Book.objects.filter(pk=pk).first()
         # 既有instance,又有data,表示修改
         ser = BookSerializer(instance=book, data=request.data)
         if ser.is_valid():
             # 重写update方法
             ser.save()  # 调用save---》内部根据instance判断是触发create还是update
             return Response(ser.data)
         return Response({'code': 102, 'msg': '修改出错', 'err': ser.errors})

一些校验

校验规则的顺序
调用父类的to_internal_value方法-》校验字段类型CharField-》通用的约束参数(max_length、min_length)-》依次校验validators中指定的校验规则 -》进入到序列化器类中调用单字段validate_XXX的校验方法-》多字段validate联合校验方法-》父类的to_internal_value方法调用结束-》进入到序列化器类中调用多字段的联合方法

to_internal_value

1.在序列化器类进行校验时,首先会调用`to_internal_value`方法,开始进行校验
2.是在所有反序列化输入开始之前会调用的一个方法,比如前端传来的数据不符合要求,可以在这里进行裁剪之后再用
# 将前端传来的字段进行大写
def to_internal_value(self, data):
    some_data = super().to_internal_value(data)
    some_data['leader']=some_data['leader'].upper() # 在中间进行数据的处理
    return super().to_internal_value(data) # 返回的是处理之前的数据
    return some_data # 可以返回处理之后的数据

validators

1.可以在序列化器字段上使用validators指定自定义校验器
2.validators 必须得指定为序列类型(往往为列表),在列表中可以添加多个校验器
3.UniqueValidator,校验器进行唯一约束的校验,必须得指定queryset参数,使用message指定具体报错信息
name = serializers.CharField(label='项目名称', help_text='项目名称', write_only=True, max_length=10, min_length=3,error_messages={'min_length': '项目名称不能少于3位'},
         validators=[UniqueValidator(queryset=Projects.objects.all(), message='项目名称不能重复')])

自定义校验

1.可以在类外面自定义校验函数
2.第一个参数为待校验的值
3.如果校验不通过,必须得抛出serializers.ValidationError(‘报错信息’)异常,同时可以指定具体得报错信息
4.需要将校验函数名放置到某一个字段的 validators列表中(不加括号)
def is_contain_keyword(value):

    if '项目' not in value:
        # 如果校验失败,必须得返回ValidationError异常对象
        # 第一个参数可以指定具体报错信息
        raise serializers.ValidationError('项目名称中必须得包含“项目”关键字')

单字段校验 validate_待校验的字段名

1.可以在序列化器类中定义对单字段进行校验的方法
2.但字段的校验方法名称,必须把validate_作为前缀,加上待校验得字段名,如:validate_待校验的字段名
3.接收的参数为前端传递的值
4.如果校验不通过必须得返回serializers.ValidationError(‘具体得报错信息’)
5.如果校验通过,往往将校验之后得值返回
6.必须返回value
def validate_name(self, value):

    if not value.endswith('项目'):
        raise serializers.ValidationError('项目名称必须以"项目"结尾')
    return value

多字段联合校验 validate

1.validate 用于多个字段的联合校验,使用固定得validate方法,会接收上面校验通过之后的字典数据
2.接收的参数attrs为前端传递的所有参数(当字段均以校验通过)
3.当所有字段定义时添加的校验规则都通过,并且每个字典得单字段校验通过得情况下,才会调用validate方法
4.如果在单字段的校验方法中校验不通过,那么不会调用validate
5.如果校验不通过,必须得返回ValidationError异常对象
6.如果校验通过,那么一般需要将校验之后的值返回
7.必须返回attrs
def validate(self, attrs):
    name = attrs.get('name')
    leader = attrs.get('leader')
    if len(name + leader) > 10:
        raise serializers.ValidationError('项目名称与项目负责人名称总长度不超过10个字节')
    return attrs

ModelSerializer

1.可以继承ModelSerializer,根据模型类来自动生成序列化器类中的字段
2.必须得指定model参数(模型类),用于指定使用的模型
3.会实现create、update方法
4.会给主键字段、DataTimeField(指定auto_now_add和auto_now参数),会添加read_only=True
5.会给有指定default参数的字段,添加required=False
6.会给有指定null参数的字段,添加allow_null=True
7.会给有指定blank参数的字段,添加allow_blank=True
8.在Meta元信息中,fields指定模型类中需要进行序列化操作的字段
     a.'__all__',指定模型类中所有的字段都需要进行序列化操作
     b.可以指定模型类中序列化操作的字段,需要在元组中指定
     c.exclude指定不需要进行序列化操作的字段
     d.如果指定了模型类中没有定义的字段,那么必须在fields元组中指定,如果fields为'__all__'或者exclude除外
class ProjectModelSerializer(serializers.ModelSerializer):

    def validate_name(self, value):
        value: str
        if not value.endswith('项目'):
            raise serializers.ValidationError('项目名称必须得以“项目”结尾')
        return value

    token = serializers.CharField(read_only=True)
    email = serializers.EmailField()

    def create(self, validated_data:dict):
        email = validated_data.pop('email')
        obj = Projects.objects.create(**validated_data)
        obj.token = '1234'
        obj.email = '123@qq.com'
        return obj

    class Meta:

        model = Projects
        fields = '__all__'  # 返回所有的序列化字段
        #fields = ('id','name', 'token', 'email') # 返回元组里写的字段
        #exclude = ('create_time', 'update_time', 'is_execute') # 返回除了元组里写的字段之外的所有字段
        """
        可以在Meta内部类的read_only_fields,统一指定需要添加read_only=True的字段
        只读的话,可以不传值
        """
       
        read_only_fields = ('is_execute','desc')
        
        """
         a.可以在Meta内部类的extra_kwargs中对自动生成的序列化字段进行修改
         b.将需要修改的字段名作为key,具体修改的内容作为value
        """
        extra_kwargs = {
            'name': {
                'label': '项目名称',
                'max_length': 10,
                'min_length': 3,
                'error_messages': {
                    'min_length': '项目名称不能少于3位',
                    'max_length': '项目名称不能超过10位'
                },
                'validators': [
                    UniqueValidator(queryset=Projects.objects.all(), message='项目名不能重复')
                ],

            },
            'create_time':{
                'format' : '%Y年%m月%d日 %H:%M'
            },
            'update_time':{
                'format': '%Y年%m月%d日 %H:%M'
            }

        }

Serializer序列化关系模型

模型表

class Publish(models.Model):
    """出版社表"""
    name = models.CharField(max_length=32,verbose_name='出版社名称')
    address = models.CharField(max_length=64,verbose_name='出版社地址')

    def __str__(self):
        return self.name

class Book(models.Model):
    """图书表"""
    title = models.CharField(max_length=32,verbose_name='书名')
    price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='书的价格')
    publish_time = models.DateTimeField(auto_now_add=True,verbose_name='出版日期')

    # 创建书籍与出版社的一对多外键字段,外键写在多的一方
    publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)

    # 创建书籍与作者的多对多外键字段
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.title

StringRelatedField

1. 用于在序列化输出时,调用关联表模型类中的__str__方法
2. 默认添加了read_only=True,只用于序列化输出,而不会反序列化输入

多对一关系中,在一的一方显示多的一方的数据,需要在一的一方加字段,如果从表没有写‘related_name=xxx’就使用‘从表名_set’

from rest_framework import serializers
from books.models import Book,Publish,Author,AuthorDetail

class BookModelSerializer(serializers.ModelSerializer):


    class Meta:
        model = Book
        fields = '__all__'


class PublishModelSerializer(serializers.ModelSerializer):

    book_set = serializers.StringRelatedField(many=True)

    class Meta:
        model = Publish
        fields = ['id','name','address','book_set']

在这里插入图片描述

多对一关系中,在多的一方显示一的一方的数据,需要在多的一方加字段,使用外键的名字,数据库里这个外键需要设置null=True,否则前端需要输入,会有问题

from rest_framework import serializers
from books.models import Book,Publish,Author,AuthorDetail


class BookModelSerializer(serializers.ModelSerializer):

    publish = serializers.StringRelatedField()

    class Meta:
        model = Book
        fields = '__all__'


class PublishModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = Publish
        fields = ['id','name','address','book_set']

没有加StringRelatedField的时候,返回的是id,加了之后,返回的是__str__里的值
在这里插入图片描述
在这里插入图片描述

PrimaryKeyRelatedField

1.父表模型对象获取从表的数据,默认使用从表模型类名小写_set
2.如果想修改默认的从表名,需要在从表models外键那里设置related_name='interfaces'
3.如果输出有多条结果,是个列表的话需要加many=True
4.在父表序列化器中可以手动指定关联字段的序列化类型
  PrimaryKeyRelatedField,指定从表的主键id值
  PrimaryKeyRelatedField,指定read_only=True,那么只输出从表外键id
  PrimaryKeyRelatedField,未指定read_only=True或者required=False,需要反序列化输入的话,需要queryset=Interfaces.objects.all()

多对一关系中,在一的一方查多的一方的数据,需要在一的一方加字段,用多的一方的表名_set

class BookModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = Book
        fields = '__all__'


class PublishModelSerializer(serializers.ModelSerializer):

    book_set = serializers.PrimaryKeyRelatedField(read_only=True,many=True)


    class Meta:
        model = Publish
        fields = '__all__'

返回的是关联字段的id值,需要指定read_only = True
在这里插入图片描述

class BookModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = Book
        fields = '__all__'


class PublishModelSerializer(serializers.ModelSerializer):

    book_set = serializers.PrimaryKeyRelatedField(many=True,queryset=Book.objects.all())


    class Meta:
        model = Publish
        fields = '__all__'

展示的是关联字段的id值,需要指定query,可以反序列化输入
在这里插入图片描述
多对一关系中,在多的一方查一的一方的数据,需要在多的一方加字段,用多的一方里的外键字段

class BookModelSerializer(serializers.ModelSerializer):

    publish = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = Book
        fields = '__all__'


class PublishModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = Publish
        fields = '__all__'

返回关联属性的主键,设置属性为read_only=True表示修改时,即使传过来的有id,也不做修改,保留原始的值!
在这里插入图片描述

class BookModelSerializer(serializers.ModelSerializer):

    publish = serializers.PrimaryKeyRelatedField(queryset=Publish.objects.all())

    class Meta:
        model = Book
        fields = '__all__'


class PublishModelSerializer(serializers.ModelSerializer):


    class Meta:
        model = Publish
        fields = '__all__'

返回关联属性的主键,设置属性为查询集,表示修改时,当你要修改时,如果查询集有,可以修改,如果没有,不可以修改!
在这里插入图片描述

SlugRelatedField

1.SlugRelatedField,用于在序列化输出或者反序列化输入时指定使用的关联模型类中的字段名
2.如果未指定read_only=True或者required=False,需要反序列化输入的话,需要queryset=Interfaces.objects.all()(指定校验时使用的查询集对象)
3.如果需要反序列化输入,那么slug_field必须得指定拥有唯一约束的字段名

多对一关系中,在一的一方查多的一方的数据,需要在一的一方加字段,用多的一方的表名_set

class BookModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = Book
        fields = '__all__'


class PublishModelSerializer(serializers.ModelSerializer):

    book_set = serializers.SlugRelatedField(many=True,read_only=True,slug_field='title')


    class Meta:
        model = Publish
        fields = '__all__'

返回关联字段slug_field='title’的值
在这里插入图片描述

class BookModelSerializer(serializers.ModelSerializer):


    class Meta:
        model = Book
        fields = '__all__'


class PublishModelSerializer(serializers.ModelSerializer):

    book_set = serializers.SlugRelatedField(many=True,queryset=Book.objects.all(),slug_field='title')


    class Meta:
        model = Publish
        fields = '__all__'

使用queryset方式
在这里插入图片描述

多对一关系中,在多的一方查一的一方的数据,需要在多的一方加字段,用多的一方里的外键字段

class BookModelSerializer(serializers.ModelSerializer):

    publish = serializers.SlugRelatedField(slug_field='name',queryset=Publish.objects.all())

    class Meta:
        model = Book
        fields = '__all__'


class PublishModelSerializer(serializers.ModelSerializer):


    class Meta:
        model = Publish
        fields = '__all__'

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值