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_set和imageandwordlevel_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")
感谢