DRF,动态指定序列化字段

现状

最近的项目是用DRF框架实现后端的接口,视图果断使用modelviewset,而也不想写curd对应好几个serializer,希望一个serializer搞定所有,于是就涉及到需要动态指定序列化和反序列化字段的问题(比如list和detail的需要的字段不一样,list往往只要少量几个关键字段做展示,detail需要更多字段),找了下网上第三方的包,没有特别合适的,于是开启了自己造轮子之路

功能

1.接口默认可以取到Serializer.Meta.fields里所有的字段,
2.查询接口(detail,list)可以传参fields动态指定需要序列化返回的字段
3.更新接口(update)可以传参fields动态指定允许反序列化保存的字段
4.可以在Serializer.Meta中配置list_fields属性,list接口用这个属性作为序列化字段,没配这个属性用原来的Meta.fields序列化;(如果同时传参fields进来做序列化,优先传参指定的fields)

DynamicFieldsModelSerializer代码

from rest_framwork import serializers


class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """支持动态指定字段的序列化器,传参fields,序列化和反序列化都支持"""
    Meta: type

    def __init__(self, *args, **kwargs):
        """支持字段动态生成的序列化器,从默认的Meta.fields中过滤,无关字段不查不序列化"""
        fields = kwargs.pop('fields', None)
        super().__init__(*args, **kwargs)
        if fields is not None:
            allow = set(fields)
            existing = set(self.fields)
            for f in existing - allow:
                self.fields.pop(f)

    def __new__(cls, *args, **kwargs):
        """list序列化时,首先使用传参的fields,默认用meta.list_fields作为序列化字段"""
        if kwargs.pop('many', False):
            fields = getattr(cls.Meta, 'list_fields', None)
            if fields and 'fields' not in kwargs:
                kwargs['fields'] = fields
            return cls.many_init(*args, **kwargs)
        return super().__new__(cls, *args, **kwargs)

调用举例

from django.db import models
from rest_framework.viewsets import ModelViewSet
from rest_framework.decorators import action
from django.http.response import HttpResponse, JsonResponse


class Task(models.Model):
    name = models.CharField(max_length=255, null=False)
    desc = models.CharField(max_length=255, null=False)
    status = models.CharField(max_length=255, null=False)


class TaskSerializer(DynamicFieldsModelSerializer):
    class Meta:
        model = Task
        fields = ['id', 'name', 'desc', 'status']  # 全部字段放这里
        list_fields = ['id', 'name']  # list用的字段,放这里


class TaskViewSet(ModelViewSet):
    queryset = Task.objects
    serializer_class = TaskSerializer

    @action(methods=['post'], detial=False)
    def close(self, request, *args, **kwargs):
        """关闭任务,只更新'status', 'desc'两个字段"""
        task = self.get_object()
        request.data['status'] = 'closed'
        serializer = self.get_serializer(task, data=request.data, partial=True, fields=['status', 'desc'])
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return HttpResponse()
        
    @action(methods=['get'], detial=False)
    def my_detail(self, request, *args, **kwargs):
        """任务详情,只返回'id', 'name', 'desc' 3个字段"""
        task = self.get_object()
        serializer = self.get_serializer(task, fields=['id', 'name', 'desc'])
        return JsonResponse(data=serializer.data)
        
    # def list(self, request, *args, **kwargs):
    #     """
    #     任务列表,只展示'id', 'name'两个字段
    #     这里不需要单独实现,TaskSerializer.__new__方法会按照Meta中的list_fields树形动态指定序列化的字段
    #     """
    
    # def retrieve(self, request, *args, **kwargs):
    #     """
    #     任务详情,展示默认所有字段 'id', 'name', 'desc', 'status'
    #     """
### Django REST framework 中序列化与反序列化的用法及区别 #### 一、序列化的作用和实现 序列化是指将复杂的 Python 对象转换成可以轻松传输或存储的数据格式,比如 JSON 或 XML。在 DRF 中,`Serializer` 类用于处理这一过程,它不仅能够把对象转为原生的 Python 数据类型以便进一步渲染为 JSON 等格式,还支持数据验证。 ```python from rest_framework import serializers from .models import Person class PersonSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=100) age = serializers.IntegerField() def create(self, validated_data): return Person.objects.create(**validated_data) def update(self, instance, validated_data): instance.name = validated_data.get('name', instance.name) instance.age = validated_data.get('age', instance.age) instance.save() return instance ``` 此代码展示了如何定义一个简单的 `PersonSerializer` 来执行基本的对象创建和更新操作[^1]。 #### 二、反序列化的过程 反序列化则是指接收客户端发送过来的数据(通常是通过 HTTP 请求),将其解析并转化为内部表示形式——即数据库中的记录或其他持久化结构。为了确保安全性和准确性,在这个过程中会对输入的数据进行严格的校验。 当接收到 POST 或 PUT 请求时,DRF 将自动调用对应的 Serializer 方法来进行必要的转换: - **POST**: 调用 `create()` 创建新实例; - **PUT/PATCH**: 则会触发 `update()` 修改现有条目; 这两个函数都需要传入经过验证后的字典参数 `validated_data`,该字典包含了所有要保存到模型里的字段值[^4]。 #### 三、两者之间的主要差异 | 特征 | 序列化 | 反序列化 | |-------------|-------------------------------------------|------------------------------------------| | 方向 | 把Python对象变成易于交换的形式 | 接收外部提交的信息,并映射回应用程序内的实体 | | 主要用途 | API响应输出 | 处理来自用户的表单提交或者其他HTTP请求体的内容 | | 关键方法 | `.data`, 返回可被渲染引擎使用的原始数据 | `.is_valid()`, 验证用户提供的信息是否合法合规 | 上述表格总结了序列化与反序列化的主要不同之处[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值