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'
    #     """
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值