序列化模块

新建项目准备

三流

标准输出流, 标准输入流, 标准错误流

'''
C:...d_projscript	est.py
import sys

sys.stdout.write('123
')  # 默认不换行
sys.stdout.write('456
')
# 123123

# res = sys.stdin.readline()  # 类似于input, 会暂停程序
# print(res)

sys.stderr.write('789
')  # 打印结果飘红, 默认不换行
sys.stderr.write('101112
')
# 异步执行, 但123与456共用一个流, 456一定在123后, 同理101112一定在789后


# C:...d_projapiexception.py
...
def exception_handler(exc, context):
    ...
    import sys
    sys.stderr.write('异常: %s
' % response.data.get('detail'))
    ...
'''

内部类

'''
class A:
    class B:  # B类的名称空间通过A类访问
        x = 10


print(A.B.x)  # 10


# C:...d_projapimodels.py
...
class User(models.Model):
    SEX_CHOICES = (
        (1, '男'),  # 元组的第一个元素存入数据库的对应字段, 第二个元素对第一个元素作说明
        (0, '女')
    )

    # verbose_name 可以修改django admin 后台显示的字段名, blank=True表示django admin后台该字段可以不填写
    username = models.CharField(max_length=64, verbose_name='用户名', blank=True)

    password = models.CharField(max_length=64, verbose_name='密码')
    sex = models.IntegerField(choices=SEX_CHOICES, default=1, verbose_name='性别')
    avatar = models.ImageField(upload_to='img', default='default.png', verbose_name='头像')  # ImageField继承FileField
    is_delete = models.BooleanField(default=False, verbose_name='是否注销')  # 开发中数据不会直接删除, 而是通过字段控制
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')

    class Meta:  # 配置类, 给所属类提供配置信息
        db_table = 'old_boy_user'  # 修改数据库显示的表名, 默认值: 所属app_类名小写
        verbose_name_plural = '用户表'  # 修改django admin 后台显示的表名

    def __str__(self):
        return self.username  # __str__方法内不能进行联表操作
        

# C:...d_projapiadmin.py
...
from . import models

admin.site.register(models.User)  # 在django admin后台注册User表
'''

在视图类中手动完成序列化操作

'''
# C:...d_projapiviews.py
from rest_framework.views import APIView
from rest_framework.response import Response
from . import models
from d_proj import settings


class UserV1APIView(APIView):
    # 单查群查
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            user_dic = models.User.objects.filter(is_delete=False, pk=pk).values('username', 'sex', 'avatar').first()
            if not user_dic:
                return Response({'status': 1, 'msg': 'pk error', }, 400)
                
            user_dic['avatar'] = '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, user_dic.get('avatar'))
            return Response({
                'status': 0,
                'msg': 'ok',
                'result': user_dic
            })

        else:
            ...

'''

Serializer序列化

序列化

  1. 后端orm操作得到数据
  2. 将数据序列化成可以返回给前端的数据类型
  3. 返回数据给前端

封装

面向对象封装

  • 数据需要多个方法处理,
  • 入口为类中的 __init__ 方法

面向过程封装:

  • 一个方法完成数据处理
'''
# C:...d_projapiviews.py
from . import serializers
from . import models


class UserV2APIView(APIView):
    # 单查群查
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            ...  # user_obj为空时, 也能处理, 结果: 所有字段为空

        else:
            # 将对象对外提供的字段, 以及整个序列化过程封装, 形成序列化类
            user_queryset = models.User.objects.filter(is_delete=False).all()

            # 根据源码, 当处理的数据中的包含多个对象时需要设置many=true
            user_ser = serializers.UserSerializer(user_queryset, many=True)  # 序列化后的对象
            user_list = user_ser.data  # 序列化后的数据

            return Response({
                'status': 0,
                'msg': 'ok',
                'result': user_list
            })
            

# C:...d_projapiserializers.py
from rest_framework import serializers
from django.conf import settings


class UserSerializer(serializers.Serializer):
    """
    	1. UserSerializer类中没有写的但是model表中有的字段不会序列化, 即不会在前端展示
        2. 字段名与字段类型要与对应模型表中的字段名与字段类型一致
        3. 可以自定义序列化字段, 用来调整对应的数据库字段返回给前端的数据, 
        4. 自定义序列化字段一定不参与反序列化
        4. 不建议自定义系列化字段名与数据库字段名重名
        5. 通过在类中自定义方法提供给自定义字段所需的字段值, 方法名为get_自定义字段名
    """
    ...
    sex = serializers.IntegerField()  # "sex": 1,
    avatar = serializers.ImageField()  # "avatar": "/media/img/111.jpg",
    
    gender = serializers.SerializerMethodField()  # "icon": "http://127.0.0.1:8000/media/img/111.jpg"
    icon = serializers.SerializerMethodField()  # "gender": "男"

    def get_gender(self, obj):  # obj为参与序列化的数据中的一个对象
        return obj.get_sex_display()

    def get_icon(self, obj):  # 在高级序列化与高级视图类中, drf默认序列化处理图片等子资源
        return '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, obj.avatar)
        

# G:...
est_frameworkserializers.py
class BaseSerializer(Field):
    ...
    def __init__(self, instance=None, data=empty, **kwargs):
        ...
        kwargs.pop('many', None)
        ...
        
        
class Serializer(BaseSerializer, ...):
	...  # 该类中没有__init__方法
'''

Serializer反序列化

反序列化

  1. 从请求对象中获取前端提交的数据
  2. 序列化类完成数据的反序列化及校验
  3. 序列化类将反序列化后的数据同步到数据库
  4. 将处理结果反馈给前端
'''
# C:...d_projapimodels.py
...
class User(models.Model):
    ...
    username = models.CharField(..., unique=True)  # unique=True, 数据库层次限制不能有重复的用户名
    
    
# C:...d_projapiviews.py
...
class UserV2APIView(APIView):
    ...
    def post(self, request, *args, **kwargs):
        request_data = request.data  # 从请求对象中获取前端提交的数据
        user_ser = serializers.UserDeSerializer(data=request_data)  # 反序列化及校验

        if user_ser.is_valid():  # 判断数据校验是否通过

            # 根据源码, save方法会判断具体是create还是update, 但因为没有绑定model中的数据库表, 所以没有具体实现方法
            user_obj = user_ser.save()  # 执行save方法会判断并执行对应的数据库操作, 返回操作后得到的新的数据对象

            return Response({'status': 0, 'msg': 'ok', 'result': serializers.UserSerializer(user_obj).data}, )
        else:
            return Response({'status': 1, 'msg': user_ser.errors, }, )
            
            
# C:...d_projapiserializers.py
from . import models


class UserDeSerializer(serializers.Serializer):
    # 系统校验字段
    username = serializers.CharField(min_length=3, max_length=16, error_messages={  # 自定义校验出错的报错信息
        'min_length': '太短',
        'max_length': '太长'
    })
    ...

    # required=False的字段前端不提供则使用model表指定的默认值, 提供了则进行反序列化及校验
    sex = serializers.BooleanField(required=False)  # required参数默认值为True

    # 自定义校验字段, 语法与系统字段没有区别, 但是需要在全钩子中将其取出, 不保存到数据库,
    re_password = serializers.CharField(min_length=3, max_length=16)

    # 局部钩子: 方法名为validate_校验的字段名
    def validate_username(self, value):  # values为通过系统校验后的对应字段值
        # print(value)  # egon
        if 'g' in value:
            raise serializers.ValidationError('用户名不能包含g')

        return value  # 字段值符合局部钩子的校验规则, 则将其返回
	
	# 全局钩子: 通常用来进行多个字段的校验
    def validate(self, attrs):  # attrs为通过系统校验后的所有字段及字段值
        # print(attrs)  # OrderedDict([('username', 'nick'), ...])
        password = attrs.get('password')
        re_password = attrs.pop('re_password')  # 获取并去除自定义校验字段
        if password != re_password:
            raise serializers.ValidationError({'re_password': '两次密码不一致'})  # key指定错误的字段
            
        return attrs  # 所有数据符合全局钩子的校验规则, 则将其返回

    def create(self, validated_data):
        return models.User.objects.create(**validated_data)

    def update(self, instance: models.User, validated_data):  # instance为要被修改的数据对象, validated_data为校验后用来修改instance的数据
        models.User.objects.filter(pk=instance.id).update()  # update方法的返回值为受影响的行
        return instance
'''

ModerSerializer序列化

'''
# C:...d_projapiserializers.py
# ModelSerializer自动处理文件对象的完整路径拼接
class UserModelSerializer(serializers.ModelSerializer):  
    # # 自定义序列化字段的方式一, 但是定义了不序列化会报错, 无法实现插拔式
    # gender = serializers.SerializerMethodField() 

    # def get_gender(self, obj):
    #     return obj.get_sex_display()

    class Meta:  # 配置类
        model = models.User  # UserModelSerializer要操作的表
        fields = ('username', 'gender', 'icon')  # 要序列化的字段, 元组形式


# C:...d_projapimodels.py
....
class User(models.Model):
    ...
    @property
    def gender(self):  # 自定义序列化字段的方式二, 不仅可以实现插拔式设计而且可以联表操作
        return self.get_sex_display()

    @property
    def icon(self):
        from django.conf import settings
        return '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, self.avatar)


# C:...d_projapiviews.py
class UserV3APIView(APIView):
    # 单查群查
    def get(self, request, *args, **kwargs):
        ...
            user_ser = serializers.UserModelSerializer(user_obj, many=False)  # 单查序列化
            ...
            # 根据源码, 当处理的数据中的包含多个对象时需要设置many=true
            user_ser = serializers.UserModelSerializer(user_queryset, many=True)  # 群查序列化
            ...
'''

ModerSerializer反序列化

'''
C:...d_projapiserializers.py
# 根据源码UserModelSerializer对create和update进行了具体实现, 并且支持所有关系下的联表操作
class UserModelSerializer(serializers.ModelSerializer):  
    ...
    # 自定义反序列化校验字段, 同Serializer, 且校验规则要么在定义时设置, 要么在钩子中设置, 在extra_kwargs中设置的无效
    re_password = serializers.CharField(min_length=3, max_length=16, write_only=True)  # 自定义反序列化字段必须设置write_only

    class Meta:
        model = models.User  # UserModelSerializer要操作的表
        fields = ('username', 'gender', 'icon', 'password', 'sex', 're_password')  # UserModelSerializer要操作的字段, 元组形式

        extra_kwargs = {  # 设置额外参数将反序列化与序列化区分开来
            'username': {  # 系统字段如果不设置, 默认都参与
                'min_length': 3,
                'max_length': 10,
            },
            'password': {  # 只参与反序列化
                'write_only': True,
                'min_length': 3,
                'max_length': 16,
            },
            'gender': {'read_only': True},  # 自定义的序列化字段默认就是read_only, 且不能修改, 但可以省略
            'sex': {  # 有默认值的字段为选填字段, 'required': True可以设置为必填字段
                'write_only': True,
                # 'required': True,
            },
        }

    # 局部钩子和全局钩子同Serializer, 和Meta同缩进
    ...
    

# C:...d_projapiviews.py
class UserV3APIView(APIView):
    ...
    def post(self, request, *args, **kwargs):
        ...
        user_ser = serializers.UserModelSerializer(data=request_data)  # ModelSerializer反序列化及校验
        
        user_ser.is_valid(raise_exception=True)  # 校验不通过时, 系统会自动抛错
        ...
'''
原文地址:https://www.cnblogs.com/-406454833/p/12118374.html