Django的REST框架多源字段

Django的REST框架多源字段

问题描述:

比方说,我在models.py有这些:Django的REST框架多源字段

#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使用的主题。
要做到这一点,我需要序列化:

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

Unfortunaly,因为它不存在,我无法使用level_set源。
我怎么能在一个单一的水平场结合puzzlelevel_setimageandwordlevel_set

其实,在深入了解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",) 

我这样做是

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

感谢