Skip to main content
 首页 » 编程设计

python之django REST framework 多源字段

2025年05月04日23findumars

假设我的 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_set 和 imageandwordlevel_set 组合到一个levels 字段中?

请您参考如下方法:

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

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",)