【问题标题】:django REST framework multi source fielddjango REST framework 多源字段
【发布时间】:2014-11-06 15:21:30
【问题描述】:

假设我的 models.py 中有这些:

#models.py
class Theme(models.Model):
    """An theme is an asset of multiple levels."""

    adventure = models.ForeignKey(Adventure)
    offset = models.PositiveSmallIntegerField()
    finished = models.BooleanField(default=False)

class Level(models.Model):
    """Abstract level representation"""

    theme = models.ForeignKey(Theme)
    offset = models.PositiveSmallIntegerField()
    finished = models.BooleanField(default=False)

    class Meta:
        abstract = True

class PuzzleLevel(Level):
    """A level for the Puzzle game"""

    points = models.CharField(max_length=200)
    image = models.ImageField()

class ImageAndWordLevel(Level):
    """A level for the ImageAndWord game"""

    word = models.CharField(max_length=30)
    image = models.ImageField()

我想在我的 api 中使用 Theme。
为此,我需要对其进行序列化:

#serializers.py
class PuzzleLevelSerializer(serializers.ModelSerializer):
    image = serializers.Field(source="image.url")

    class Meta:
        model = PuzzleLevel
        fields = ("offset", "finished", "points", "image")

class ImageAndWordLevelSerializer(serializers.ModelSerializer):
    image = serializers.Field(source="image.url")

    class Meta:
        model = ImageAndWordLevel
        fields = ("offset", "finished", "word", "image")

class ThemeSerializer(serializers.ModelSerializer):
    levels = serializers.Field(source="level_set")

    class Meta:
        model = Theme
        fields = ("offset", "finished", "levels")

很遗憾,我无法使用 level_set 源,因为它不存在。
如何将 puzzlelevel_setimageandwordlevel_set 组合在一个 levels 字段中?

【问题讨论】:

    标签: python django serialization field django-rest-framework


    【解决方案1】:

    实际上,在深入研究了 REST 框架的源代码之后,我得到了一个解决方案:
    我编写了一个能够管理多个来源的自定义字段。

    class MultiSourceField(serializers.Field):
        """
        A custom field to use when you want to
        join multiple sources into a single field.
        Example :
            my_field = MultiSourceField(source=["attr1.subattr", "attr2.subattr"])
        It can also handle serializers, a small example :
            rel_field = MultiSourceField(source=[Serializer(source="rel"), "attr2"])
        """
    
        def field_to_native(self, obj, field_name):
            if obj is None:
                return self.empty
    
            sources = self.source
            value = []
            for source in sources:
                if isinstance(source, serializers.BaseSerializer):
                    value += source.field_to_native(obj, "")
                else:
                    #setting self.source to source in order to use the parent method
                    self.source = source
                    value.append(super(MultiSourceField, self).field_to_native(obj,
                        field_name))
                    #reverting self.source after the parent method call
                    self.source = sources
            return value
    

    现在,我的主题序列化器看起来像这样:

    class ThemeSerializer(serializers.ModelSerializer):
        levels = MultiSourceField(source=[
            PuzzleLevelSerializer(source="puzzlelevel_set"),
            ImageAndWordLevelSerializer(source="imageandwordlevel_set")
        ])
    
        class Meta:
            model = Theme
            fields = ("offset", "finished", "levels",)
    

    【讨论】:

    • field_to_native() 方法在 DRF 3.0 中被删除
    【解决方案2】:

    您可以使用 MethodFiel (DRF=3.x)
    未测试

    serializers.SerializerMethodField()
        levels = serializers.SerializerMethodField()
    
        def get_levels(self, obj):
            value = []
            s1 = PuzzleLevelSerializer(obj, many=True, source="puzzlelevel_set")
            s2 = ImageAndWordLevelSerializer(obj, many=True, source="imageandwordlevel_set")
    
            value.extend(s1.data)
            value.extend(s2.data)
            return value
    

    【讨论】:

      【解决方案3】:

      我已经这样做了

      student = StudentSerializer(source="from_person") or 
                StudentSerializer(source="to_person")
      

      谢谢

      【讨论】:

        猜你喜欢
        • 2018-10-03
        • 2021-09-03
        • 2013-01-15
        • 2017-08-29
        • 2015-09-19
        • 1970-01-01
        • 2019-11-20
        • 1970-01-01
        • 2016-09-18
        相关资源
        最近更新 更多