Django-序列化器

本文详细讲解了如何在 Django 中使用 DRF 的序列化器进行数据校验,包括单字段和多字段验证,以及如何与数据库交互,如创建和更新操作。通过实例演示了自定义校验器和序列化器方法,助您理解序列化器在API开发中的关键作用。
摘要由CSDN通过智能技术生成


序列化器主要作用是进行一些数据校验和序列化操作。

一、 实现序列化

在子应用中新建serializers.py文件。

from rest_framework import serializers

# 定义序列化类,需继承serializers.Serializer
class ProjectSerializer(serializers.Serializer):
    # 将需要校验和序列化的字段加进来,变量名和字段类型需要和models.py中一致
    # 默认定义哪些字段,那么哪些字段就会序列化输出,同时这些字段也必须输入(传递)
    name = serializers.CharField()
    leader = serializers.CharField()

在views.py文件中使用序列化器

class ProjectView(View):
    def get(self, request):
        qs = Projects.objects.all()

        # instance接收查询集对象;当查询集对象有多条数据需要定义many=True,只有一条数据不定义many
        serializer = serializers.ProjectSerializer(instance=qs, many=True)
        # data属性可以取出列表嵌套字典格式的数据,直接返回前端(返回哪些数据是由序列化类决定的)
        projects_list = serializer.data

        return JsonResponse(projects_list, safe=False, json_dumps_params={"ensure_ascii": False})
  • 这里需要注意一下,之前的代码,更新操作其实更新的是全部字段,那么我们都知道,更新的时候其实是不校验必填项的,所以更新方法中调用serializers时,只要加上partial=True,我们就只会校验已传字段,对未传字段不予理会。
    serializer = serializers.ProjectSerializer(instance=qs, data=json_dict, partial=True)

1.1 serializers参数

name = serializers.CharField(label='项目名称')
label='字段名称' HTML页面展示API页面时,显示的字段名称
help_text='字段说明' HTML页面展示API页面时,显示的字段帮助提示信息
max_length=10' 字段允许的最大长度
min_length=3' 字段允许的最小长度
write_only=True' 该字段必须得输入(反序列化输入),但无需输出(序列化输出),默认False
read_only=True' 该字段无需输入(反序列化输入),但必须得输出(序列化输出),该字段不会做校验。默认False
required=False' 反序列化时无须输入,默认True
default=‘默认值’ 如果没有输入,反序列化时使用的默认值
allow_null=True' 该字段允许传入None(传参时是"参数名":null),默认False
allow_blank=True' 该字段允许传入空值(传参时是"参数名":""),默认False
error_messages={'字段约束参数名': '自定义的错误提示信息'}' 自定义错误提示
trim_whitespace=True' 将前后的空白字符截掉
format='%Y年%m月%d日 %H:%M:%S' 格式化输出(如果输入中文报编码错误,需要在文件开始加上locale.setlocale(locale.LC_CTYPE, 'chinese')
validators=[UniqueValidator(queryset=Projects.objects.all(), message='项目名不能重复'),自定义方法名])'' 自定义校验器。validators有很多自带的校验规则可以使用,例如UniqueValidator。

参数约束关系

  • write_only和read_only不能同时为True
  • read_only和required不能同时为True
  • required=True和default=‘默认值’不能同时设置

1.2 父表获取从表信息

父表的serializers.py文件

class ProjectSerializer(serializers.Serializer):
	#父表模型对象获取从表的数据,默认使用“从表模型类名小写_set”;PrimaryKeyRelatedField只能输出从表的id
    interfaces_set = serializers.PrimaryKeyRelatedField(label='所属接口的id', help_text='所属接口的id',
                                                        many=True, read_only=True)

    #如果未指定read_only=True或者required=False,那么必须得指定queryset(指定校验时使用的查询集对象)
    interfaces_set = serializers.PrimaryKeyRelatedField(label='所属接口的id', help_text='所属接口的id',
                                                        many=True, queryset=Interfaces.objects.all())
                                                        
	#如果不想使用“从表模型类名小写_set”作为外键,那么可在子表的model.py中定义外键字段时加上参数“related_name='interfaces'”
    interfaces = serializers.PrimaryKeyRelatedField(label='所属接口的id', help_text='所属接口的id',
                                                    many=True, queryset=Interfaces.objects.all())
    
    # StringRelatedField用于在序列化输出时,调用关联模型类中的__str__方法
    # StringRelatedField默认添加了read_only=True,只用于序列化输出,而不会反序列化输入
    interfaces = serializers.StringRelatedField(label='所属接口名称', help_text='所属接口名称', many=True)

    # SlugRelatedField用于在序列化输出或者反序列化输入时,指定使用的关联模型类中的字段名(slug_field)
    # 如果未指定read_only=True或者required=False,那么必须得指定queryset(指定校验时使用的查询集对象)
    # 如果需要反序列化输入,那么slug_field必须得指定拥有唯一约束的字段名
    interfaces = serializers.SlugRelatedField(label='所属接口名称', help_text='所属接口名称', many=True,
                                              slug_field='tester', queryset=Interfaces.objects.all())

二、 实现入参的校验

校验规则为序列化器类中定义的字段规则。
views.py

# 给data传参,那么可以实现数据校验,data必须得传递Python中的基本类型(字典或者嵌套字典的列表)
serializer = serializers.ProjectSerilizer(data=python_data)

# 必须得调用is_valid方法,才会开始进行校验。如果校验通过,会返回True,否则返回False
if not serializer.is_valid():
	# errors属性用于获取错误提示信息,往往为字典类型;必须得先调用is_valid方法才有errors
	err = serializer.errors
	return JsonResponse(err, json_dumps_params={"ensure_ascii": False}, status=400)
# serializer.validated_data可以获取校验通过之后的数据;validated_data属性,必须调用is_valid()方法后,才能获取
obj = Projects(**serializer.validated_data)
  • is_valid(raise_exception=True) 校验不通过会自动抛出异常
  • 必须先调用is_valid()才可以调用validated_dataerrorsdata属性。

2.1 自定义校验器

  • 自定义校验器需要在字段中加上validators参数
  • validators必须得指定为序列类型(往往为列表),在列表中可以添加多个校验器
  • UniqueValidator校验器进行唯一约束的校验,必须得指定queryset参数,使用message指定具体报错信息

2.1.1 校验器类外定义的校验器

  • 自定义校验函数,直接将函数名放置到validators列表中
# 校验项目名称中是否包含‘项目’的方法
def is_contain_keyword(value):
	# value为前端传递的项目名称
    if '项目' not in value:
        # 如果校验失败,必须得返回ValidationError异常对象;参数可以指定具体报错信息
        raise serializers.ValidationError('项目名称中必须得包含“项目”')

class ProjectSerilizer(serializers.Serializer):
    name = serializers.CharField(validators=[
                                     UniqueValidator(queryset=Projects.objects.all(), message='项目名不能重复'),
                                     is_contain_keyword
                                 ])

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

2.1.2 校验器类里定义的校验器

校验器类里定义的校验器是最后执行的,如果前面有校验不通过的,不会执行校验器类里定义的校验器。

单字段校验
class ProjectSerilizer(serializers.Serializer):
	# 方法名必须为“validate_需校验的字段名”
	def validate_name(self, value):
		# value为前端传递的name的值
        if not value.endswith('项目'):
        	# 如果校验不通过,必须得返回ValidationError异常对象
            raise serializers.ValidationError('项目名称必须得以“项目”结尾')
        # 如果校验通过,那么一般需要将校验之后的值返回
        return value
多字段联合校验

单字段校验通过后才会执行多字段联合校验

class ProjectSerilizer(serializers.Serializer):
    # 方法名固定为validate,接收的参数为前端传递的所有参数(dict)
    def validate(self, attrs):
        name = attrs.get('name', '')
        leader = attrs.get('leader', '')
        # 如果校验不通过,必须得返回ValidationError异常对象
        if len(name + leader) > 10:
            raise serializers.ValidationError('项目名与项目负责人名称总长度不超过10个字符')
		# 如果校验通过,那么一般需要将校验之后的数据返回
        return attrs
to_internal_value

序列化器类中的to_internal_value是在序列化器类进行校验时,首先调用的方法。

class ProjectSerilizer(serializers.Serializer):
	# 方法名固定为to_internal_value,接收的参数为经过is_valid验证的数据(dict)
    def to_internal_value(self, data):
        some_data = super().to_internal_value(data)
        some_data['leader'] = some_data['leader'].upper()
        return some_data
to_representation

可以自定义返回字段某个值的内容或者新增字段返回

class ProjectSerilizer(serializers.Serializer):
	def to_representation(self, instance):
		instance["age"] = instance.name.age
		instance= super(xxSerializer, self).to_representation(instance)
校验顺序:

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

三、在序列化器中操作数据库

3.1 create

在serializers.py文件中添加create方法,当调用serializers.save()时,会自动执行create方法。

class ProjectSerilizer(serializers.Serializer):
	# validated_data往往为校验通过之后的数据(字典类型)
    def create(self, validated_data: dict):
        # 在序列化器对象调用save方法时,可以传递关键字参数,这些关键字参数会被validated_data接收,注意存入数据库前要将增加的参数删掉,不然会报错
        obj = Projects.objects.create(**validated_data)
        # 必须得将创建的模型类对象返回
        return obj

修改views.py文件中的post方法。

class ProjectViews(View):
        try:
            python_data = json.loads(request.body.decode('utf-8'))
        except Exception:
            return JsonResponse(err_msg, json_dumps_params={"ensure_ascii": False}, status=400)

        serializer = serializers.ProjectSerilizer(data=python_data)
        if not serializer.is_valid():
            err = serializer.errors
            return JsonResponse(err, json_dumps_params={"ensure_ascii": False}, status=400)

        # 序列化器对象调用save方法时,会调用序列化器类中的create方法,进行数据创建操作
        serializer.save()
        # obj = Projects(**serializer.validated_data)
        # obj.save()
        # serializer = serializers.ProjectSerilizer(instance=obj)
        return JsonResponse(serializer.data, json_dumps_params={"ensure_ascii": False})

3.2 update

在serializers.py文件中添加update方法,当调用serializers.save()时,会自动执行update方法。

  • 注意:create方法和update方法都是调用serializers.save()时自动执行,区别是save传参带既有instance又有validated_data时,执行update方法,只传validated_data时,执行create方法。
class ProjectSerilizer(serializers.Serializer):
	# validated_data往往为校验通过之后的数据(字典类型),instance为待更新的模型类对象
    def update(self, instance, validated_data):
        # 在序列化器对象调用save方法时,可以传递关键字参数,这些关键字参数会被validated_data接收
        instance.name = validated_data.get('name') or instance.name
        instance.leader = validated_data.get('leader') or instance.leader
        instance.desc = validated_data.get('desc') or instance.desc
        instance.is_execute = validated_data.get('is_execute') or instance.is_execute
        instance.save()
        # 必须得将更新的模型类对象返回
        return instance

修改views.py文件中的put方法。

class ProjectDetailView(View):
    def put(self, request, pk):
        try:
            python_data = json.loads(request.body.decode('utf-8'))
        except Exception:
            return JsonResponse(err_msg, json_dumps_params={"ensure_ascii": False}, status=400)

		obj = Projects.objects.get(id=pk)
        serializer = serializers.ProjectSerilizer(instance=obj, data=python_data)
        if not serializer.is_valid():
            err = serializer.errors
            return JsonResponse(err, json_dumps_params={"ensure_ascii": False}, status=400)

        # 5、数据更新
        # obj.name = serializer.validated_data.get('name') or obj.name
        # obj.leader = serializer.validated_data.get('leader') or obj.leader
        # obj.desc = serializer.validated_data.get('desc') or obj.desc
        # obj.is_execute = serializer.validated_data.get('is_execute') or obj.is_execute
        # obj.save()

        # 序列化器对象调用save方法时,会调用序列化器类中的update方法,进行数据更新操作
        serializer.save()
        # serializer = serializers.ProjectSerilizer(instance=obj)
        return JsonResponse(serializer.data, json_dumps_params={"ensure_ascii": False}, status=201)
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值