Skip to content

Instantly share code, notes, and snippets.

@walkermanx
Created December 30, 2017 14:47
Show Gist options
  • Save walkermanx/862555548aaa97bd3ff9ea4b4053f755 to your computer and use it in GitHub Desktop.
Save walkermanx/862555548aaa97bd3ff9ea4b4053f755 to your computer and use it in GitHub Desktop.
Django Serializers高级用法之动态修改Fields参数

###一言不合,上代码

class SlidesSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Slides
        fields = ('id', 'title', 'image', 'url', 'no',)

使用Django开发的童鞋应该很面熟上面的代码吧,因为在开发中常常会编写如上的各种Serializer类来为我们的Model类数据进行序列化操作。通常上面这个SlidesSerializer类的主要作用就是将其Meta类中指定Model对象models.Slides序列化成由其 fields属性声明的那些字段组成的字符串

#序列化之后的models.Slides对象
{'id': 2, 'title': '道地良品', 'image': '/daodi.png', 'url': 'www.daodikeji.com', 'no': 'DD_BJ_001'}

一切都挺ok,突然有一天,小五童鞋觉得除了idimagetitle字段,其它字段都不需要序列化,于是他给models.Slides又写了一个精简版的SerializerSlidesLiteSerializer

class SlidesSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Slides
        fields = ('id', 'title', 'image', 'url', 'no',)

#精简序列化版
class SlidesLiteSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Slides
        fields = ('id', 'title','image',)

##额,好像有点Low...

的确,怎么可以则个样子啊,虽然也能解决问题,但要是再来个需要id与其它四个字段分别俩俩搭配的需求,岂不是又得整一堆Serializer...
作为一个有点强迫症的码农,我表示不能忍啊
于是,参照官网api文档,我对SlidesLiteSerializer进行了一番改造

class SlidesSerializer(serializers.ModelSerializer):
    """
     此处的`fields`字段是用来替换上面Serializer内部Meta类中指定的`fields`属性值
    """

    def __init__(self, *args, **kwargs):
        # 在super执行之前
        # 将传递的`fields`中的字段从kwargs取出并剔除,避免其传递给基类ModelSerializer
        # 注意此处`fields`中在默认`self.fields`属性中不存在的字段将无法被序列化 也就是`fields`中的字段应该      
        # 是`self.fields`的子集
        fields = kwargs.pop('fields', None)

        super(BaseModeSerializer, self).__init__(*args, **kwargs)

        if fields is not None:
            # 从默认`self.fields`属性中剔除非`fields`中指定的字段 
            allowed = set(fields)
            existing = set(self.fields.keys())
            for field_name in existing - allowed:
                self.fields.pop(field_name)

    class Meta:
        model = models.Slides
        fields = ('id', 'title', 'image', 'url', 'no',)

现在,来试试:

>>> print SlidesSerializer(sides)
{'id': 2, 'title': '道地良品', 'image': '/daodi.png', 'url': 'www.daodikeji.com', 'no': 'DD_BJ_001'}
>>> print SlidesSerializer(sides, fields=('id', 'title'))
{'id': 2, 'title': '道地良品'}
>>> print SlidesSerializer(sides, fields=('id', 'title','image'))
{'id': 2, 'title': '道地良品', 'image': '/daodi.png'}

##Nice!!!

Ps:建议将构造器部分代码实现放置于基类Serializer,然后将Model类对应的Serializer实现类继承该基类,酱紫,所有继承该基类的Serializer均能实现Fields参数的动态修改

希望对大家有所帮助,如果喜欢,不要小气,给个♥呗!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment