DRF初识攻坚(二)-----序列器(serializer)、视图(APIview)

一、基本概念

此节了解即可,下一篇是重点实用篇

1.1 概念图解

在这里插入图片描述

  • 序列化:将服务端数据结构类型(模型类对象)转换为客户端数据结构格式(字典、JSON)
  • 反序列化:将客户端数据结构类型(字典、JSON)转换为服务端数据结构类型(模型类对象)
  • 序列化器:封装了序列化和反序列化(含数据校验)的所有操作

1.2 序列化器类图继承关系

在这里插入图片描述

  • Serializer类:类似Django的Form类,比较底层,可定制程度最高的类,需要高度定制DRF的序列化器的时候选择
  • ModelSerializer类:封装化的序列化器,可定制程度较低,常规功能基本具备,常用

二、序列化器写法

2.1 示例表间关系

在这里插入图片描述
具体ORM生成请移步(点击此处)

2.2 序列化器字段

  • 常规写法:字段名=serializers.数据类型(字段选项)

  • 特性:

    • 按需写入
      • GET方法:把需要提供给客户端的字段才写进来,字段选项细控
      • POST\PUT\PATCH方法:需要客户端提供的字段才写进来,字段选项细控
    • 字段对应:除模型声明属性(见2.3中StuSerializer),序列化器字段名定要和模型里的字段名相同
    • 字段功能:用在反序列化阶段验证数据,序列化阶段写了的字段名才会返回给客户端
  • 字段选项通用参数

    参数名称说明
    read_only仅用于序列化输出,默认False,若为True则相当于同时设置了required=False
    write_only仅用于反序列化输入,默认False,序列化时不输出该字段
    required反序列化时必须输入,默认True,否则报错
    default默认值,序列化实例时,如果实例中不存在值,则将使用默认值,设置则意味着required=False
    many定义当前字段是否为可迭代对象,若为True,返回键值对为"key": [value1,value2...]
    默认为False,返回键值对"key": value1
    allow_null表明该字段是否允许传入None,默认False
    validators应用于传入字段输入的验证器函数列表,并且会引发验证错误或仅返回
    error_messages包含错误代码为键,错误消息为值的字典
    label备注,用于HTML展示API页面时,显示的字段名称
  • 字段选项常用参数

    参数名称作用
    max_length最大长度
    min_lenght最小长度
    allow_blank是否允许为空,不与allow_null同时使用
    trim_whitespace是否清除前后空白字符
    max_value最小值
    min_value最大值
  • 字段写法(含默认设置)

    字段意义字段构造注释
    布尔BooleanField()默认为required=False,若需要需显式声明
    布尔+NoneNullBooleanField()
    字符串CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)对应CharField和TextField
    邮箱EmailField(max_length=None, min_length=None, allow_blank=False)
    正则表达式RegexField(regex, max_length=None, min_length=None, allow_blank=False)
    数字字母短横线SlugField(maxlength=50, min_length=None, allow_blank=False)正则字段,验证正则模式 [a-zA-Z0-9-]+
    网址URLField(max_length=None, min_length=None, allow_blank=False)
    整型IntegerField(max_value=None, min_value=None)
    浮点型FloatField(max_value=None, min_value=None)
    十进制DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)max_digits: 允许的最大位数,decimal_palces: 小数位数,coerce_to_string返回字符串值,则设置为 True
    外键字段PrimaryKeyRelatedField(read_only=True, many=True)read_only=True或queryset=models.表名.objects.all()必须二选一,many选项若为可迭代对象则需要填
    时间+日期DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
    纯日期DateField(format=api_settings.DATE_FORMAT, input_formats=None)
    纯时间TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
    选择字段ChoiceField(choices)对于文本选择,allow_blank 应该是首选,而对于数字或其他非文本选择,allow_null 应该是首选
    复合选择字段MultipleChoiceField(choices)
    文件FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    图片ImageField(max_length=None,allow_empty_file=False,
    use_url=UPLOADED_FILES_USE_URL)

2.3 序列化操作

2.3.1 继承serializers的序列化器

  • 文件位置:/api/serializers.py
  • 代码:此序列化器包含序列化操作必要内容完整写法见反序列化操作的序列化器
    from rest_framework import serializers
    
    class StuSerializer(serializers.Serializer):
        '''Stu表序列器'''
       	# 主键定义read_only属性,反序列化时此属性会被丢弃
        id = serializers.IntegerField(read_only=True)
        name = serializers.CharField()
        # 外键字段之穷举法:调用外键所在表的序列器
        stu_detail = StuDetailSerializer()
        # 外键字段之穷举法:调用外键所在表的序列器,many选项:一对多、多对多字段必须写
        book = BookSerializer(many=True)
    	    '''
    	    # 外键字段之主键法:只深入到外键所在表的主键,many选项:一对多、多对多字段必须写
    		stu_detail = serializers.PrimaryKeyRelatedField(read_only=True)
    		
    		# 视图显示结果均为
    		# stu序列器: {'id': 1, 'name': 'sam', 'stu_detail': 2, 'book': [1, 2], 
    					'is_marked': True}		
    		'''
        # 模型声明属性:此序列器字段不在数据库中,可自定义添加,返回响应后清除数据
        is_marked = serializers.BooleanField(default=True)
    
    class StuDetailSerializer(serializers.Serializer):
        '''StuDetail表序列器'''
        id = serializers.IntegerField(read_only=True)
        birthday = serializers.DateField()
        height = serializers.DecimalField()
        # 可选项序列器字段写法
        gender_choices = (
            (0, 'female'),
            (1, 'male'),
            (2, 'secret'),
        )
        gender = serializers.ChoiceField(choices=gender_choices)
    
    class BookSerializer(serializers.Serializer):
        '''Book表序列器'''
        id = serializers.IntegerField(read_only=True)
        name = serializers.CharField()
        publish = PublishSerializer()
        	'''外键之反向跨表:
        	stu_set = StuSerializer(many=True)
        	或下面这个
        	stu_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
    	    
    	    视图显示结果为
    		Book序列器: {'id': 2, 'name': 'chinese', 'publish': 2, 
    					'stu_set': [1, 2]}
    		'''
    
    class PublishSerializer(serializers.Serializer):
        '''Publish表序列器'''
        id = serializers.IntegerField(read_only=True)
        name = serializers.CharField()
    
  • 外键字段写法(PrimaryKeyRelatedField)
    • 多对多字段名写法(隐式生成)
      • 正向跨表:字段为:外键名,选项queryset, many=True
      • 反向跨表:字段为:外键所在表的表名小写_set,选项read_only=True, many=True
      • 表示法:上面两字段不可同时用穷举法,可同时用主键法,一穷一主,则穷举法在前
    • 一对多字段名写法
      • 正向跨表: 字段为:外键名,选项queryset, many=False
      • 反向跨表:字段为:外键所在表的表名小写_set,选项read_only=True, many=True
      • 表示法:上面两字段不可同时用穷举法,可同时用主键法,一穷一主,则穷举法在前

    一对多判定:外键所在的表为多,”多“表要加many=True

2.3.2 继承APIView的视图

  • view.py代码
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from api import models, serializers
    
    class Test(APIView):
        def get(self, request):
            """序列化单个模型数据"""
            # 1、读取模型对象
            student = models.Stu.objects.first()
            # 2、实例化序列化器(将模型类对象传给对应的序列化器)
            serializer = serializers.StuSerializer(instance=student)
            # 3、返回结果,通过data属性获取序列化器转换数据后的结果
            print('stu序列器:', serializer.data)
    
            student_detail = models.StuDetail.objects.first()
            serializer = serializers.StuDetailSerializer(instance=student_detail)
            print('StuDetail序列器:', serializer.data)
    
            book = models.Book.objects.first()
            serializer = serializers.BookSerializer(instance=book)
            print('Book序列器:', serializer.data)
    
            """序列化多个模型数据"""
            # 1、读取模型对象(多个)
            publish = models.Publish.objects.all()
            # 2、实例化序列化器对象,many=True:告诉序列化器内部,instance值为列表,需循环遍历
            serializer = serializers.PublishSerializer(instance=publish, many=True)
            # 3、返回结果,通过data属性获取序列化器转换数据后的结果
            print('Publish序列器:', serializer.data)
    
            return Response("操作完成")
    

    APIView内获取请求各部分方法:

    • 获取请求头:res = request.headers.get('Host'),打印全部print(request.headers)
    • get请求体:res = request.query_params.get('id'),打印全部print(request.query_params)
    • put/post/delete请求体:res = request.data.get('id'),打印全部print(request.data)
    • 列表:如果键值对的值为列表,需通过res = request.data.getlist('id[]')获取,id[]print(request.data)查找对应值
    • 前端axios请求封装:传送门第三节

2.3.3 显示结果

  • 有序字典OrderedDict:
    • 释义
      因为python内置的基础类型的字典是无序的,所以这种无序字典无法保证存储时的键值对顺序和提取时候的顺序一致,有序字典和无序字典,除了声明不一样以外,对于成员的读取和操作是一样的。
    • 取值方法
      for item in serializer.data:
      	print(item["birthday"])
      
  • 结果
    #########################################################################
    '''stu序列器:'''
    {
        'id': 1,
        'name': 'sam',
        'stu_detail': OrderedDict(
            [
                ('id', 2),
                ('birthday', '1987-08-08'),
                ('height','175.5'),
                ('gender', 2)
            ]
        ),
        'book':[
            OrderedDict(
                [
                    ('id', 1),
                    ('name', 'math'),
                    ('publish', OrderedDict(
                            [
                                ('id', 2),
                                ('name', 'social publisher')
                            ]
                        )
                    )
                ]
            ),
            OrderedDict(
                [
                    ('id', 2), 
                    ('name', 'chinese'), 
                    ('publish', OrderedDict(
                            [
                                ('id', 2),
                                ('name', 'social publisher')
                            ]
                        )
                    )
                ]
            )
        ], 
        'is_marked': True
    }
    #########################################################################
    '''StuDetail序列器:'''
    {'id': 1, 'birthday': '1999-12-09', 'height': '165.4', 'gender': 1}
    #########################################################################
    '''Book序列器:'''
    {
        'id': 1,
        'name': 'math',
        'publish': OrderedDict(
            [
                ('id', 2),
                ('name', 'social publisher')
            ]
        )
    }
    #########################################################################
    '''Publish序列器:'''
    [
        OrderedDict([('id', 1), ('name', 'central publisher')]),
        OrderedDict([('id', 2), ('name', 'social publisher')])
    ]
    

2.4 反序列化操作

  • 校验
    • 数据类型校验:CharField等
    • 选项校验:max_length等
  • 入库:重写序列器create、update函数

2.4.1 继承serializers的序列化器

  • 文件位置:/api/serializer.py
  • 代码
    from rest_framework import serializers
    from api import models
    
    
    class StuDetailSerializer(serializers.Serializer):
        '''StuDetail表序列器'''
        # 主键定义read_only属性,反序列化时此属性会被丢弃
        id = serializers.IntegerField(read_only=True)
        birthday = serializers.DateField()
        # 十进制:精确计数,相对于浮点数:近似值  最大数位4,包含1个小数位
        height = serializers.DecimalField(max_digits=4, decimal_places=1)
        # 可选项序列器ChoiceField字段写法
        gender_choices = (
            (0, 'female'),
            (1, 'male'),
            (2, 'secret'),
        )
        gender = serializers.ChoiceField(choices=gender_choices)
        # 外键字段写法:外键所在的表为一对多中的“多”,需加many选项,用于标识可迭代对象
    	# PrimaryKeyRelatedField:反向跨表用read_only,正向跨表用queryset
        stu_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
    
        def create(self, validated_data):
        	# 常规模型新增数据:字典法,对应POST方法
            studetail_obj = models.StuDetail.objects.create(**validated_data)
            # 返回给视图函数serializer.save()
            return studetail_obj
    
        def update(self, instance, validated_data):
        	# get方法为Python的字典方法,正常取到字典的键birthday的值赋值:对应PUT方法
        	# 否则取instance.birthday给等号左侧instance.birthday赋值:对应PATCH方法
            instance.birthday = validated_data.get("birthday", instance.birthday)
            instance.height = validated_data.get("height", instance.height)
            instance.gender = validated_data.get("gender", instance.gender)
            # 将修改后的数据提交数据库写入
            instance.save()
            # 返回给视图函数serializer.save()
            return instance
    
    
    class PublishSerializer(serializers.Serializer):
        '''Publish表序列器'''
        id = serializers.IntegerField(read_only=True)	    
        name = serializers.CharField(max_length=50)
        # 外键字段写法:外键所在的表为一对多中的“多”,需加many选项,用于标识可迭代对象
        # PrimaryKeyRelatedField:反向跨表用read_only,正向跨表用queryset
        book_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
        # book_set = BookSerializer(read_only=True, many=True)
    
        """自定义字段校验规则:重写validate方法"""
        def validate(self, attrs):
            # attrs为客户端传进来并被序列器处理过的字典
            name = attrs['name']
            if "0" in name:
                # 返回客户端 {"non_field_errors": ["名字不能包含字符0"}
                raise serializers.ValidationError("名字不能包含字符0")
            # 校验通过,则原样返回
            return attrs
    
        def create(self, validated_data):
        	# 常规模型新增数据:字典法,对应POST方法
            pub_obj = models.Publish.objects.create(**validated_data)
            # 返回给视图函数serializer.save()
            return pub_obj
    
        def update(self, instance, validated_data):
        	# get方法为Python的字典方法,正常取到字典的键birthday的值赋值:对应PUT方法
        	# 否则取instance.birthday给等号左侧instance.birthday赋值:对应PATCH方法
            instance.name = validated_data.get("name", instance.name)
            # 将修改后的数据提交数据库写入
            instance.save()
            # 返回给视图函数serializer.save()
            return instance
    
    
    class StuSerializer(serializers.Serializer):
        '''Stu表序列器'''
        # 主键定义read_only属性,反序列化时此属性会被丢弃
        id = serializers.IntegerField(read_only=True)
        name = serializers.CharField(max_length=12)
        # 外键字段写法:外键所在的表为一对多中的“多”,需加many选项,用于标识可迭代对象
    	# PrimaryKeyRelatedField:反向跨表用read_only,正向跨表用queryset
        stu_detail = serializers.PrimaryKeyRelatedField(queryset=models.StuDetail.objects.all(), many=False)
        # book为Stu表隐性生成的,正反向跨表由此判断
        book = serializers.PrimaryKeyRelatedField(queryset=models.Book.objects.all(), many=True)
    
        def create(self, validated_data):
        	# 常规模型新增数据:字典法,对应POST方法
        	# 弹出字典中的外键键值对,在create方法指定修改
            stu_detail = validated_data.pop("stu_detail")
            # 弹出字典中的外键键值对,在add方法指定修改
            book = validated_data.pop("book")
            # create方法:字典不可含外键id,可含外键object,若确需用id,须明确指定如下
            stu_obj = models.Stu.objects.create(stu_detail=stu_detail, **validated_data)
            # add方法对应ORM数据库模型manytomany方法新增数据方法
            stu_obj.book.add(*book)
            # 返回给视图函数serializer.save()
            return stu_obj
    
        def update(self, instance, validated_data):
        	# get方法为Python的字典方法,正常取到字典的键birthday的值赋值:对应PUT方法
        	# 否则取instance.birthday给等号左侧instance.birthday赋值:对应PATCH方法
            instance.name = validated_data.get("name", instance.name)
            instance.stu_detail = validated_data.get("stu_detail", instance.stu_detail)
            book = validated_data.get("book", instance.book)
            # set方法对应ORM数据库模型manytomany方法,重置外键,非新增
            instance.book.set(book)
            # 将修改后的数据提交数据库写入
            instance.save()
            # 返回给视图函数serializer.save()
            return instance
    
    
    class BookSerializer(serializers.Serializer):
        '''Book表序列器'''
        # 主键定义read_only属性,反序列化时此属性会被丢弃
        id = serializers.IntegerField(read_only=True)
        name = serializers.CharField(max_length=12)
        # 外键字段写法:外键所在的表为一对多中的“多”,需加many=True,用于标识可迭代对象
    	# PrimaryKeyRelatedField:反向跨表用read_only,正向跨表用queryset
        publish = serializers.PrimaryKeyRelatedField(queryset=models.Publish.objects.all(), many=False)
        stu_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
    
        def create(self, validated_data):
        	# 常规模型新增数据:字典法,对应POST方法
        	# 弹出字典中的外键键值对,在create方法指定修改
            publish = validated_data.pop("publish")
            # create方法:字典不可含外键id,可含外键object,若确需用id,须明确指定如下
            book_obj = models.Book.objects.create(publish=publish, **validated_data)
            # 返回给视图函数serializer.save()
            return book_obj
    
        def update(self, instance, validated_data):
        	# get方法为Python的字典方法,正常取到字典的键birthday的值赋值:对应PUT方法
        	# 否则取instance.birthday给等号左侧instance.birthday赋值:对应PATCH方法
            instance.name = validated_data.get("name", instance.name)
            instance.publish = validated_data.get("publish", instance.publish)
            # 将修改后的数据提交数据库写入
            instance.save()
            # 返回给视图函数serializer.save()
            return instance
    
    

2.4.2 继承APIView的视图

  • view.py代码
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from api import models, serializers
    
    
    class Test(APIView):
        # 查操作,按需打开,return只能返回最后一个serializer.data
        def get(self, request):
            """序列化操作,同2.3.1条"""
            """StuDetail表的序列化操作"""
            # stu_detail = models.StuDetail.objects.all()
            # serializer = serializers.StuDetailSerializer(instance=stu_detail, many=True)
            # print('StuDetail序列器:', serializer.data)
    
            """Publish表的序列化操作"""
            # publish = models.Publish.objects.all()
            # serializer = serializers.PublishSerializer(instance=publish, many=True)
            # print('Publish序列器:', serializer.data)
    
            """Stu表的序列化操作"""
            student = models.Stu.objects.all()
            serializer = serializers.StuSerializer(instance=student, many=True)
            print('stu序列器:', serializer.data)
    
            """Book表的序列化操作"""
            # book = models.Book.objects.all()
            # serializer = serializers.BookSerializer(instance=book, many=True)
            # print('Book序列器:', serializer.data)
    
            return Response(serializer.data)
    
        # 增操作
        def post(self, request):
            """Studetail表的反序列化操作"""
            studetail_data = {
                "birthday": "1993-7-10",
                "height": 168,
                "gender": 1
            }
            serializer = serializers.StuDetailSerializer(data=studetail_data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
    
            """Publish表的反序列化操作"""
            publish_data = {"name": "publish of east"}
            serializer = serializers.PublishSerializer(data=publish_data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
    
            """Stu表的反序列化操作"""
            stu_data = {
                "name": "jackson",
                "stu_detail": 4,
                "book": [1, 3]
            }
            serializer = serializers.StuSerializer(data=stu_data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
    
            """Book表的反序列化操作"""
            book_data = {
                "name": "art",
                "publish": 2,
            }
            serializer = serializers.BookSerializer(data=book_data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
    
            return Response("操作完成")
    
        # 改操作
        def put(self, request):
            """Studetail表的反序列化操作"""
            # 模拟客户端提交来的json数据,后面补充
            studetail_data = {
                "birthday": "1995-7-10",
                "height": 175,
                "gender": 2
            }
            # 选定需要修改的模型对象
            studetail_obj = models.StuDetail.objects.last()
            # 1、给序列化器传两个参数instance,data,表示修改,instance为数据库模型数据,data为客户提供数据
            serializer = serializers.StuDetailSerializer(instance=studetail_obj, data=studetail_data)
            # 2、进行数据校验,raise_exception=True在反序列化时验证失败时抛出serializers.ValidationError
            # REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应
            serializer.is_valid(raise_exception=True)
            # 3、数据入库,调用序列化器的update方法
            serializer.save()
    
            """Publish表的反序列化操作"""
            publish_dic = {"name": "publish of west"}	        
            publish_object = models.Publish.objects.last()	        
            serializer = serializers.PublishSerializer(instance=publish_object, data=publish_dic)
            serializer.is_valid(raise_exception=True)	        
            serializer.save()
    
            """Stu表的反序列化操作"""
            stu_data = {
                "name": "jack",
                "stu_detail": 4,
                "book": [2, 3]
            }
            stu_obj = models.Stu.objects.last()
            serializer = serializers.StuSerializer(instance=stu_obj, data=stu_data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
    
            """Book表的反序列化操作"""
            book_data = {
                "name": "sports",
                "publish": 1
            }
            book_obj = models.Book.objects.last()
            serializer = serializers.BookSerializer(instance=book_obj, data=book_data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
    
            return Response("操作完成")
    
        # 删操作
        def delete(self, request):
            # 因为数据库模型外键有on_delete=models.CASCADE,
            # 所以以下数据删除有顺序,只能先删除有外键的表,再删除没有外键的表
            """Book表的反序列化操作"""
            models.Book.objects.last().delete()
    
            """Publish表的反序列化操作"""
            models.Publish.objects.last().delete()
    
            """Stu表的反序列化操作"""
            last_stu = models.StuDetail.objects.last()
            # 清空多对多的中间表
            last_stu.clear()
            last_stu.delete()
    
            """StuDetail表的反序列化操作"""
            models.StuDetail.objects.last().delete()
    	
            return Response("操作完成")
    	# 局部改操作(不需提供完整信息即可修改)
        def patch(self, request):
            """各表的反序列化操作"""
            # 与def put 相同,仅需修改以下一句即可(增加partial选项)
            # serializer=serializers.StuDetailSerializer(instance=studetail_obj,data=studetail_data,partial=True)
            return Response("操作完成")
    

    APIView内获取请求各部分方法:

    • 获取请求头:res = request.headers.get('Host'),打印全部print(request.headers)
    • get请求体:res = request.query_params.get('id'),打印全部print(request.query_params)
    • put/post/delete请求体:res = request.data.get('id'),打印全部print(request.data)
    • 前端axios请求封装:传送门第三节

跳转至总篇目录

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值