DRF单表序列化

DRF单表序列化

​ 后台的数据多以后台类的对象存在,经过序列化后,就可以格式化成能返回给前台的数据。

​ 定义一个全局models:

​ models.py:

from django.db import models

class User(models.Model):
    CHOICES_SEX = ((0, '男'), (1, '女'))
    name = models.CharField(max_length=64)
    age = models.IntegerField(default=0)
    height = models.DecimalField(max_digits=5, decimal_places=2, default=0)
    icon = models.ImageField(upload_to='icon', default='default.png')
    sex = models.IntegerField(choice=CHOICE_SEX, default=0)
    # 若以迁移数据库后新增自选,需要允许为空,或者设置默认值,假定pwd为新增字段
    pwd = models.CharField(max_length=64, null=Ture)
    
    # 自定义插拔序列化字段:替换了在Serializer类中自定义的序列化字段(SerializerMethodField)
    # 自定义插拔序列化字段一定不参与反序列化过程
    @property
    def gender(self):
        return self.get_sex_display()
    
    class Meta:
        db_table = 'ob_user'
        verbose_name = '用户表'
        verbose_name_plural = verbose_name
        
    def __str__(self):
        return self.name

一、Serializer组件

​ 序列化步骤:

​ 1、ORM操作数据库拿到资源数据。

​ 2、格式化成能返回给前台的数据(序列化)。

​ 3、返回格式化后的数据。

​ views.py:

from rest_framework.views import APIView
from rest_framework.response import Response
from . import models, serializers
from rest_framework import status

class UserAPIView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        
        if pk:
        	user_obj = models.User.object.filter(pk=pk).first()
            if not user_obj:
                return Response({
                    'status' : 1,
                    'msg': '单查 error'
                })
            # 完成序列化
            user_ser= serializers.UserSerializer(user_obj, many=False)
            user_data = user_ser.data
            
            return Response({
                'status': 0,
                'msg': '单查 ok',
                'results': user_data
            })
        # 多查
        user_query = models.User.objects.all()
        # 完成序列化
        user_list_data = serializers.UserSerializer(user_query, many=Ture).data
        return Response({
            'status': 0,
            'msg': '群查 ok',
            'results': user_list_data
        })

​ 反序列化:

​ 1、从请求对象中拿到前台的数据。

​ 2、校验前台数据是否合法。

​ 3、反序列化成后台Model对象与数据库交互。

	def post(self, request, *args, **kwargs):
        request_data = request.data
        
        # 反序列化目的:封装数据的校验过程,以及数据库交互的过程
        user_ser = serializer.UserDeserializer(data=request_data)
    	# 调用反序列化的校验规则:系统规则,自定义规则(局部钩子,全局钩子)
        result = user_ser.isvalid()
        
        if result:
            # 校验通过,可以与数据库进行交互:增(create),改(update)
            user_obj = user_ser.save()
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': serializers.UserSerializer(user_obj).data
            })
        else:
            # 校验失败,返回错误信息
            return Response({
                'status': 1,
                'msg': user_ser.errors
            }, status=status.HTTP_400_BAD_REQUEST)

​ 数据校验:

​ serializers.py:

from rest_framework import serializers

class UserSerializer(serializers.Serializer):
    
    # model已有的属性字段校验
    #   如果要参与序列化,名字一定要与model的属性同名
    #   如果不参与序列化的model属性,在序列化类中不做声明
    name = serializers.CharField()
    age = serializers.IntegerField()
    height = serializers.DecimalField(max_digits=5, decimal_places=2)
    
    # 自定义序列化字段,序列化的属性值由方法来提供,
    #   方法的名字:固定为 get_属性名,
    #   方法的参数:序列化对象,序列化的model对象
    #   强烈建议自定义序列化字段名不要与model已有的属性名重名
    gender = serializers.SerializerMethodField()
    def get_gender(self, obj)
    	return obj.get_sex_display()
    
from . import models

class UserDeserializer(serializers.Serializer):
    # 系统校验规则
    # 系统必须反序列化的字段
    # 序列化属性名不是必须与model属性名对应,但是与之对应会方便序列化将校验通过的数据与数据库进行交互
    name = serializers.CharField(min_length=3, max_length=64, error_messages={
        'required': '姓名必填',
        'min_length': '太短',
    })
    pwd = serializers.CharField(min_length=3, max_length=64)
    
    # 系统可选的反序列化字段:没有提供不进行校验(数据库中有默认值或可以为空),提供了就进行校验
    age = serializers.IntegerField(min_value=0, max_value=150, required=False)
    # 自定义反序列化字段:一定参与校验,且要在校验过程中,将其从入库的数据中取出,剩余与model对应的数据才会入库
    re_pwd = serializers.CharField(min_length=3, max_length=64)

    # 自定义校验规则:局部钩子,全局钩子
    # 局部钩子:validate_字段名(self, 字段值)
    # 规则:成功返回value,失败抛异常
    def validate_name(self, value):
        if len(value) < 2:
            raise serializers.ValidationError('不能短于两位')
        return value
    
    # 全局钩子:validate(self, 所有校验的数据字典)
    # 规则:成功返回attrs,失败抛异常
    
    def validata(self, attrs):
        pwd = attrs.get('pwd')
        re_pwd = attrs.pop('re_pwd')
        if pwd != re_pwd:
            raise serializers.ValidationError({'re_pwd': '两次密码不一致'})
        retuen attrs
        
    # create重写,完成入库
    def create(self, validated_data):
        return models.User.objects.create(**validated_data)

二、ModelSerializer组件

​ 如果要使用序列化器对应的是Django的模型类,DRF提供了ModelSerializer模
型类序列化器,可以快速创建一个Serializer类。

​ ModelSerializer与常规的Serializer相同,但提供了:

​ 1、基于模型类自动生成一系列字段

​ 2、基于模型类自动为Serializer生成validators,比如unique_together

​ 3、包含默认的create()和update()的实现

​ views.py:

from rest_framework.views import APIView
from rest_framework.response import Response
from . import models, serializers
from rest_framework import status

class UserAPIView(APIview):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            user_obj = models.User.Objects.filter(pk=pk).first()
            if not user_obj:
            	return Response({
                    'status': 1,
                    'msg': '单查 error'
                })
            
            # 完成序列化
            user_data = serializers.UserModelSerializer(user_obj, many=False).data
            return Response({
                'status': 0,
                'msg': '单查 ok',
                'results': user_data
            })
        # 群查
        user_query = models.User.objects.all()
        # 完成序列化
        user_list_data = serializers.UserModelSerializer(user_query, many=True).data
        return Response({
            'status': 0,
            'msg': '群查 ok',
            'results': user_list_data
        })
    
    # 单增
   	def post(self, request, *args, **kwargs):
        request_data = request.data
        user_ser = serializers.UserModelSerializer(data=request_data)
        
		# 校验失败,直接抛异常,反馈异常信息给前台,只要校验通过,代码才会往下执行
        result = user_ser.is_valid()
        if result:
            user_obj = user_ser.save()
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': serializers.UserModelSerializer(user_obj).data
            })
        else:
            # 校验失败,返回错误信息
            return Response({
                'status': 1,
                'msg': user_ser.errors
            }, status=status.HTTP_400_BAD_REQUEST)

​ 数据校验:

​ modelserializer.py

from rest_framework.serializers import ModelSerializer
from . import models
# 整合序列化与反序列化
class UserModelSerizlizer(ModelSerializer):
    # 将序列化类与Model类进行绑定
    # 设置序列化与反序列化所有字段(并划分序列化字段与反序列化字段)
    # 设置反序列化的局部与全局钩子
    
    # 自定义反序列化字段,校验规则只能在声明自定义反序列化字段时设置,且一定是write_only
    re_pwd = serializers.CharField(min_length=3, max_length=64, write_only=True)
    class Meta:
        model = models.User
        fields = ['name', 'age', 'height', 'gender', 'pwd', 're_pwd']
		extra_kwargs = {
            'name': {
                'required': True,
                'min_length': 3,
                'error_messages': {
                    'min_length': '太短'
                }
            },
            'age': {
                'required': Ture,  # 数据库有默认值或可以为空字段,required默认为False
                'min_value': 0
            },
            'pwd': {
                required: Ture,
                'write_only': Ture,  # 只参与反序列化
            },
            'gender': {
                'reader_only': Ture,  # 只参与序列化
            },
        }
        
	def validate_name(self, value):
        if len(value) < 2:
            raise serializers.ValidationError('不能短于两位')
        return value
    
    def validate(self, attrs):
        pwd = attrs.get('pwd')
        re_pwd = attrs.pop('re_pwd')
        if pwd != re_pwd:
            raise serializers.ValidationError({'re_pwd', '两次密码不一致'})
        return attrs
    
    # 无需重写create,ModelSerializer已封装好了

三、单表序列化总结

3.1 序列化

一、视图类的三步操作

​ 1)ORM操作数据库拿到资源数据

​ 2)格式化(序列化)成能返回给前台的数据

​ 3)返回格式化后的数据

二、视图类的序列化操作

​ 1)直接将要序列化的数据传给序列化类

​ 2)要序列化的数据如果是单个对象,序列化的参数many为False,数据如果是多个对象(list,queryset)序列化的参数many为True

三、序列化类

​ 1)model了中要反馈给前台的字段,在序列化类中要进行声明,属性名必须就是model的字段名,且Field类型也要保持一致(不需要明确规则)

​ 2)model了中不需要反馈给前台的字段,在序列化类中不需要声明(省略)

​ 3)自定义序列化字段用 SerializerMethodField() 作为字段类型,该字段的值来源于 get_自定义字段名(self, obj) 方法的返回值

3.2 反序列化

一、视图类的三步操作

​ 1)从请求对象中拿到前台的数据

​ 2)校验前台数据是否合法

​ 3)反序列化成后台Model对象与数据库交互

二、视图类的反序列化操作

​ 1)将要反序列化的数据传给序列化类的data参数

​ 2)要反序列化的数据如果是单个字典,反序列化的参数many为False,数据如果是多个字典的列表,反序列化的参数many为True

三、反序列化类

​ 1)系统的字段,可以在Field类型中设置系统校验规则(name=serializers.CharField(min_length=3))

​ 2)required校验规则绝对该字段是必校验还是可选校验字段(默认required为True,数据库字段有默认值或可以为空的字段required可以赋值为False)

​ 3)自定义的反序列字段,设置系统校验规则同系统字段,但是需要在自定义校验规则中(局部、全局钩子)将自定义反序列化字段取出(返回剩余的数据与数据库交互)

​ 4)局部钩子的方法命名 validate_属性名(self, 属性的value),校验规则为 成功返回属性的value 失败抛出校验错误的异常

​ 5)全局钩子的方法命名 validate(self, 所有属性attrs),校验规则为 成功返回attrs 失败抛出校验错误的异常

3.3 单表序列化

​ 1)序列化与反序列功能可以整合成一个类,该类继承ModelSerializer

​ 2)继承ModelSerializer类的资源序列化类,内部包含三部分 Meta子类、局部钩子、全局钩子

​ 注:create和update方法ModelSerializer已经重写了,使用不需要重写

​ 3)在Meta子类中: 用model来绑定关联的Model类 用fields来设置所有的序列化反序列化字段 用extra_kwargs来设置系统的校验规则

​ 4)重要的字段校验规则:

​ read_only校验规则,代表该字段只参与序列化

​ write_only校验规则,代表该字段只参与反序列化

​ required校验规则,代表该字段在反序列化是是否是必填(True)还是选填(False),不能和read_only一起使用(规则冲突)

​ 规则细节:

​ 如果一个字段有默认值或是可以为空,没设置required规则,默认为False,反之默认值为True

​ 如果一个Model字段即没有设置read_only也没设置write_only,该字段默认参与序列化及反序列化

​ 5)自定义序列化字段:在Model类中,定义方法属性(可以返回特殊值,还可以完成连表操作),在序列化类的fields属性中可以选择性插拔

​ 6)自定义反序列化字段:在Serializer类中,自定义校验字段,校验规则也只能在声明字段时设置,自定义的反序列化字段(如re_pwd),必须设置write_only为True

原文地址:https://www.cnblogs.com/tangceng/p/11901117.html