DRF--序列化器类中的to_internal_value,to_representation方法,save,create,update方法

1.to_internal_value方法

                def to_internal_value(self, data):

        1.1 to_internal_value方法,是所有字段开始校验时的入口方法,最先调用

        1.2 会依次对序列化器类的各个字段进行校验,校验顺序:

对字段类型校验->validators列表中的校验规则从前往后依次验证->从后往前依次验证min_length,max_value等其他规则->校验器内部单字段校验规则->to_internal_value调用结束->校验器内部多字段联合校验规则validate方法       

2. to_representation方法        

                def to_representation(self, instance):

        2.1 to_representation方法是所有字段开始进行序列化输出的入口方法,最先被调用

        2.2 可以在序列化输出之前对字段值进行定制改造,改造后再返回

3.save

        3.1 先看下类视图中的处理逻辑 

                # projects/views.py

import json

from django.http import HttpResponse, JsonResponse

# 子应用视图
from django.views import View
from projects import models
from projects.serializers import ProjectSerializer

class JsonDecoderError111(BaseException):
    pass


class ProjectsView(View):
    """
    类视图
    :param View: 继承自from django.views import View
    :return: HttpResponse对象
    """

    def get(self, request):
        # 查询所有项目信息
        # GET /projects/
        projects_list = []
        qs = models.Projects.objects.all()
        # for item in qs:
        #     projects_list.append(
        #         {
        #             'id': item.id,
        #             'name': item.full_name,
        #             'leader': item.leader,
        #             'create_time': item.create_time,
        #             'update_time': item.update_time,
        #         }
            # )
        serializer = ProjectSerializer(instance=qs, many=True)
        return JsonResponse(serializer.data, safe=False)

    def post(self, request):
        # 新建项目
        # POST /projects/  json格式参数
        try:
            python_data = json.loads(request.body)
        except:
            return JsonResponse({'msg': '参数有误'}, status=400)

        serializer = ProjectSerializer(data=python_data)
        # 需要调用序列化器serializer的is_valid()方法才能开始校验输入数据
        if not serializer.is_valid():
            return JsonResponse({'msg': serializer.errors}, status=501)

        # 校验通过才创建项目
        pro_obj = models.Projects.objects.create(**serializer.validated_data)

        return JsonResponse(serializer.validated_data, safe=False, status=201)


class ProjectDetailView(View):

    def get(self, request, pk):
        # 查询指定项目
        # GET /projects/<int:pk>/
        pro_obj = models.Projects.objects.get(id=pk)
        serializer = ProjectSerializer(instance=pro_obj)
        return JsonResponse(serializer.data, status=203)

    def put(self, request, pk):
        # 修改项目
        # PUT /projects/<int:pk>/ json格式参数
        try:
            python_data = json.loads(request.body)
        except:
            return JsonResponse({'msg': '参数有误1'}, status=400)

        serializer = ProjectSerializer(data=python_data)

        if not serializer.is_valid():
            return JsonResponse({'msg': serializer.errors}, status=400)

        count = models.Projects.objects.filter(id=pk).update(**serializer.validated_data)
        result = {
            'data': serializer.validated_data,
            'msg': '更新成功',
            'count': count,
        }
        return JsonResponse(result, status=203)

    def delete(self, request, pk):
        # 删除项目
        # DELETE /projects/<int:pk>
        status = models.Projects.objects.filter(id=pk).delete()
        result = {
            'msg': f'删除{pk}成功',
            'count': status,
        }
        return JsonResponse(result, safe=False, status=203)


从代码中可以看到,post方法和update方法是有很多重复的代码的,部分重复的代码可以在序列化器中进行封装,这样使用同一个序列化器的地方,就可以直接调用封装的方法. 

        3.2  views.py中的类视图中在调用ProjectSerializer序列化器类时,

                可以同时给参数instance和data传值

                3.2.1 若只给data传值,未给instance传值

                        说明是反序列化校验的数据是为了创建对象,不是为了更新对象

                3.2.2 若同时给instance和data传值

                        说明是为了给instance指定的对象更新数据

                3.2.3 序列化器对象创建后,必须在调用is_valid()方法通过,才能使用序列化器对象.data属

                        性,来获取序列化输出的数据(内部过程:会把validated_data数据作为数据源,自动去

                        参照序列化器内部定义的字段,对比生成可以序列化输出的模型对象)

                3.2.4 serializer.save()方法可传任意参数,若传递的参数与前端传递过来反序列化校验的

                        数据的key值一致,则会将前端的数据覆盖,在序列化器内部的create方法中可以将

                        save(myname='xx',age=xx)过滤pop出来,这样不会应为save()方法传递的参数导致

                        反序列化校验失败了,而且还能在create方法中得到其他想要的数据,适应场景:特定

                        权限的用户才能创建用户,这里可以将用户信息或权限通过save()方法传递给create

                        方法判断.

4.create

        当类视图中的序列化器对象创建时,若只指定了data参数值,则会调用序列化器类中的create()方法创建对象

  def create(self, validated_data: dict):
        """
        序列化器类中定义create方法,视图中调用save()方法时,若只给serializer传了data参数的值,
        则会自动调用此方法
        :param validated_data: 反序列化已经校验通过数据
        :return: 模型对象
        """
        myname = validated_data.pop('myname')
        age = validated_data.pop('age')
        pro_obj = Projects.objects.create(**validated_data)
        return pro_obj

5.update 

当类视图中的序列化器对象创建时,若同时指定了instance参数和data参数值,则会调用序列化器类中的update()方法更新对象

   def update(self, instance, validated_data):
        """
        序列化器类中定义update方法,视图中调用save()方法时,若给serializer同时传了instance和data参数的值,
        则会自动调用此方法
        :param instance: 待更新数据的对象
        :param validated_data: 待更新的具体数据
        :return: 更新数据后的对象
        """
        instance.full_name = validated_data.get('full_name') or instance.full_name
        instance.leader = validated_data.get('leader') or instance.leader
        instance.is_execute = validated_data.get('is_execute') or instance.is_execute
        # 更新后通过.save()方法保存生效
        instance.save()

        return instance

         输出

        更新前:

        更新后:

创建序列化器对象总结: 

        1. 只传递instance参数:

                a.调用is_valid(),errors,validated_data都会报错.

                b.不能调用save()方法

                c.调用data属性,可以进行序列化输出

        2.只传递data参数:

                a.必须调用is_valid()方法对数据进行校验,调用errors,validated_data不会报错.

                b.调用save()方法会指定调用序列化器类的create()方法

                c.调用data属性,可以进行序列化输出(如果有调用save()方法,并且create方法有返回模型

                        对象的话,那么会把模型对象作为data属性序列化器输出的源数据;如果没有调用

                        save()方法,那么会把validated_data作为data属性序列化输出的源数据)

        3.同时传递instance参数和data参数      

                a.必须调用is_valid()方法对数据进行校验,调用errors,validated_data不会报错.

                b.调用save()方法会指定调用序列化器类的update()方法

                c.调用data属性,可以进行序列化输出(如果有调用save()方法,并且update方法有返回模型

                        对象的话,那么会把模型对象作为data属性序列化器输出的源数据;如果没有调用

                        save()方法,那么会把validated_data作为data属性序列化输出的源数据)

附代码:

        # projects/views.py

import json

from django.http import HttpResponse, JsonResponse

# 子应用视图
from django.views import View
from projects import models
from projects.serializers import ProjectSerializer

class JsonDecoderError111(BaseException):
    pass


class ProjectsView(View):
    """
    类视图
    :param View: 继承自from django.views import View
    :return: HttpResponse对象
    """

    def get(self, request):
        # 查询所有项目信息
        # GET /projects/
        qs = models.Projects.objects.all()
        serializer = ProjectSerializer(instance=qs, many=True)
        return JsonResponse(serializer.data, safe=False)

    def post(self, request):
        # 新建项目
        # POST /projects/  json格式参数
        try:
            python_data = json.loads(request.body)
        except:
            return JsonResponse({'msg': '参数有误'}, status=400)

        serializer = ProjectSerializer(data=python_data)
        # 需要调用序列化器serializer的is_valid()方法才能开始校验输入数据
        if not serializer.is_valid():
            return JsonResponse({'msg': serializer.errors}, status=501)

        # 校验通过才创建项目
        # pro_obj = models.Projects.objects.create(**serializer.validated_data)
        # save()方法优化53行代码
        serializer.save(myname='小白', age=18)

        return JsonResponse(serializer.validated_data, safe=False, status=201)


class ProjectDetailView(View):

    def get(self, request, pk):
        # 查询指定项目
        # GET /projects/<int:pk>/
        pro_obj = models.Projects.objects.get(id=pk)
        serializer = ProjectSerializer(instance=pro_obj)
        return JsonResponse(serializer.data, status=203)

    def put(self, request, pk):
        # 修改项目
        # PUT /projects/<int:pk>/ json格式参数
        try:
            python_data = json.loads(request.body)
        except:
            return JsonResponse({'msg': '参数有误1'}, status=400)

        # 获取待更新的对象
        pro_obj = models.Projects.objects.get(id=pk)
        serializer = ProjectSerializer(instance=pro_obj, data=python_data)

        if not serializer.is_valid():
            return JsonResponse({'msg': serializer.errors}, status=400)

        # count = models.Projects.objects.filter(id=pk).update(**serializer.validated_data)
        # result = {
        #     'data': serializer.validated_data,
        #     'msg': '更新成功',
        #     'count': count,
        # }

        # save()方法优化82~87行代码
        serializer.save()

        return JsonResponse(serializer.data, status=203)

    def delete(self, request, pk):
        # 删除项目
        # DELETE /projects/<int:pk>
        status = models.Projects.objects.filter(id=pk).delete()
        result = {
            'msg': f'删除{pk}成功',
            'count': status,
        }
        return JsonResponse(result, safe=False, status=203)


         # projects/serializers.py

# 此文件定义子应用projects具备的模型类对应的序列化器
from rest_framework import serializers
from rest_framework.validators import UniqueValidator

from interfaces.models import Interfaces
from projects.models import Projects


class InterfacesSerializer(serializers.Serializer):
    """自定义的序列化器类实际上是Field的子类"""
    id = serializers.IntegerField(label='接口id', help_text='接口名称', read_only=True)
    name = serializers.CharField(label='接口名称', help_text='接口名称',
                                 max_length=50, min_length=2)
    tester = serializers.CharField(label='接口测试人员', help_text='接口测试人员',
                                   max_length=50, min_length=2)
    projects = serializers.CharField(label='接口所属项目id', help_text='接口所属项目id',
                                     read_only=True)


def is_contain_keyword(values: str):
    """
    定义一个校验规则,判断字段是否以'xx项目'结尾
    :param values: 序列化器中待校验的字段
    :return:
    """
    # 如果校验失败,要raise serializers.ValidationError异常,并可以指定异常信息提示
    if not values.endswith('项目'):
        raise serializers.ValidationError("项目名称必须以'项目'结尾")
    # 如果校验成功,不做任何处理,接着往下校验
    pass


class ProjectSerializer(serializers.Serializer):
    """
    """
    id = serializers.IntegerField(label='项目id', help_text='项目id',
                                  read_only=True)
    full_name = serializers.CharField(label='项目名称', help_text='项目名称', max_length=20, min_length=4,
                                      error_messages={"max_length": "项目名称不能超过20个字符",
                                                      "min_length": "项目名称不能小于4个字符"},
                                      validators=[UniqueValidator(queryset=Projects.objects.all(),
                                                                  message='项目名称不能重复'),
                                                  is_contain_keyword]
                                      )
    leader = serializers.CharField(label='项目负责人', help_text='项目负责人', max_length=20, min_length=2)
    is_execute = serializers.BooleanField(label='项目是否执行', help_text='项目是否执行', required=False)
    desc = serializers.CharField(label='项目描述', help_text='项目描述', allow_null=True, allow_blank=True)
    create_time = serializers.DateTimeField(label='项目从创建时间', help_text='项目创建时间',
                                            format='%Y-%m-%d %H:%M:%S', read_only=True)
    update_time = serializers.DateTimeField(label='项目跟新时间', help_text='项目更新时间',
                                            read_only=True)

    # 将指定的从表序列化器类作为interfaces_set以返回多个字段值,因为InterfacesSerializer类也是Field的子类,所以可以作为字段属性
    interfaces_set = InterfacesSerializer(label='所属接口信息', help_text='所属接口信息',
                                          read_only=True, many=True)

    def validate_full_name(self, attr: str):
        """
        自定义单字段校验规则:validate_xxx
        1。若校验失败,跟序列化器类外部定义的校验方法一样raise serializers.ValidationError()
        2。若校验成功,则需要return xxx,这个xxx会赋值给被校验的字段full_name
        :param attr: 待校验值
        :return: attr
        """
        if not attr.startswith('春田'):
            raise serializers.ValidationError("项目名必须以'春田'开头")
        return attr

    def validate(self, attrs: dict):
        """
        自定义多字段校验规则:validate,例如注册模块的输入密码与确认密码功能,会用到多字段联合校验
        1。若校验失败,跟序列化器类外部定义的校验方法一样raise serializers.ValidationError()
        2。若校验成功,则需要return xxx,这个xxx会赋值给被校验的字段
        :param attrs: 待校验的多个关联字段
        :return: attrs
        """
        if not attrs.get("full_name").startswith("春田") or not attrs.get('is_execute'):
            raise serializers.ValidationError("项目名必须以'春田'开头 或者 is_execute为True")
        return attrs

    def to_internal_value(self, data):
        """
        1.to_internal_value方法是所有字段开始进行反序列化输入并校验的入口方法,最先被调用
        2.可在对各单个字段校验结束后,return tmp之前对数据进行定制化修改
        :param data:
        :return:
        """
        tmp = super().to_internal_value(data=data)
        return tmp

    def to_representation(self, instance):
        """
        1.to_representation方法是所有字段开始进行序列化输出的入口方法,最先被调用
        2.可以在序列化输出之前对字段值进行定制改造,改造后再返回
        :param instance:
        :return:
        """
        tmp = super().to_representation(instance=instance)
        return tmp

    def create(self, validated_data: dict):
        """
        序列化器类中定义create方法,视图中调用save()方法时,若只给serializer传了data参数的值,
        则会自动调用此方法
        :param validated_data: 反序列化已经校验通过数据
        :return: 模型对象
        """
        myname = validated_data.pop('myname')
        age = validated_data.pop('age')
        pro_obj = Projects.objects.create(**validated_data)
        return pro_obj

    def update(self, instance, validated_data):
        """
        序列化器类中定义update方法,视图中调用save()方法时,若给serializer同时传了instance和data参数的值,
        则会自动调用此方法
        :param instance: 待更新数据的对象
        :param validated_data: 待更新的具体数据
        :return: 更新数据后的对象
        """
        instance.full_name = validated_data.get('full_name') or instance.full_name
        instance.leader = validated_data.get('leader') or instance.leader
        instance.is_execute = validated_data.get('is_execute') or instance.is_execute
        # 更新后通过.save()方法保存生效
        instance.save()

        return instance

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
DRFDjango REST Framework)是一个用于构建Web API的强大框架,而partial_updateDRF的一个方法,用于部分更新资源。 在RESTful API,我们通常使用PUT方法来更新整个资源对象。但是,在某些情况下,我们可能只想更新资源对象的一部分字段,而不是整个对象。这时,partial_update方法就派上用场了。 partial_update方法允许我们通过发送部分数据来更新资源对象。具体来说,我们可以使用HTTP PATCH请求来调用partial_update方法,并只发送需要更新的字段和对应的值。DRF会根据请求提供的数据,部分更新资源对象的字段。 使用partial_update方法有以下几个步骤: 1. 定义一个继承自DRF的视图类,并指定serializer_class属性为对应的序列化器类。 2. 在视图类定义partial_update方法,处理部分更新逻辑。 3. 在urls.py配置对应的URL路由。 下面是一个示例代码片段,展示了如何使用partial_update方法: ```python from rest_framework import generics from .serializers import MyModelSerializer from .models import MyModel class MyModelPartialUpdateView(generics.UpdateAPIView): serializer_class = MyModelSerializer queryset = MyModel.objects.all() def partial_update(self, request, *args, **kwargs): instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=True) serializer.is_valid(raise_exception=True) self.perform_update(serializer) return Response(serializer.data) ``` 这是一个基于类的视图,继承自DRFUpdateAPIView。在partial_update方法,我们获取要更新的对象实例,然后使用传入的数据进行部分更新。最后,返回更新后的数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chuntian_tester

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值