我目前正在尝试熟悉DRF,并在完成教程时使用了这些序列化程序
class EmbeddedAnswerSerializer(serializers.ModelSerializer):
votes = serializers.IntegerField(read_only=True)
class Meta:
model = Answer
fields = ('id', 'text', 'votes',)
class QuestionSerializer(serializers.ModelSerializer):
answers = EmbeddedAnswerSerializer(many=True,source='answer_set')
class Meta:
model = Question
fields = ('id', 'answers', 'created_at', 'text', 'user_id',)
这些是模型
class Question(models.Model):
user_id = models.CharField(max_length=36)
text = models.CharField(max_length=140)
created_at = models.DateTimeField(auto_now_add=True)
class Answer(models.Model):
question = models.ForeignKey(Question,on_delete=models.PROTECT)
text = models.CharField(max_length=25)
votes = models.IntegerField(default=0)
我的问题出在问题序列化器的声明中
answers = EmbeddedAnswerSerializer(many=True,source='answer_set')
many = True
和来源=' answer_set'的目的是什么? ?
我从文档中读到了关于many=True
您仍然可以对序列化程序类使用many = True参数。 值得注意的是,许多=真正的论点透明地创造了一个 ListSerializer实例,允许列表和的验证逻辑 要在REST框架代码库中干净地分隔的非列表数据。
我对这意味着什么感到困惑?如果我从代码中删除many=True
,我会收到错误
AttributeError at /api/quest/1/2/
Got AttributeError when attempting to get a value for field `text` on serializer `EmbeddedAnswerSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `RelatedManager` instance.
Original exception text was: 'RelatedManager' object has no attribute 'text'.
任何人都可以解释many=True
做了什么以及source
字段做了什么?
答案 0 :(得分:4)
可能不是最好的解释,有人可以添加更多详细信息,但简要many=True
告诉序列化器它将采用对象列表进行serilizing proccess。换句话说,它只是一个触发器,允许您指定是否一次序列化,以及多个对象,或只是单个对象。
source
指定对象的哪个属性应该使用当前序列化程序字段进行序列化。
实践中这一行
answers = EmbeddedAnswerSerializer(many=True, source='answer_set')
表示您要使用answer_set
序列化Question
对象的EmbeddedAnswerSerializer
属性。由于answer_set
是对象列表,因此您应添加 many=True
作为参数,以使序列化程序知道它将与对象列表而不是单个对象一起使用。
答案 1 :(得分:3)
通过@neverwalkaloner
添加上述答案 many=True
表示有多个对象(可迭代)被传递给序列化程序。传递此字段会触发many_init
内的BaseSerializer
自动创建ListSerializer
实例。
源代码段:
def __new__(cls, *args, **kwargs):
# We override this method in order to automagically create
# `ListSerializer` classes instead when `many=True` is set.
if kwargs.pop('many', False):
return cls.many_init(*args, **kwargs)
return super(BaseSerializer, cls).__new__(cls, *args, **kwargs)
这告诉DRF哪个对象属性提供字段的值。默认假设是在序列化程序上声明的字段名称与提供该值的对象实例上的字段相同。如果不是这样,source
允许您显式提供序列化程序将查找值的对象实例。这里可以看到def bind(self, field_name, parent)
内部serializers.fields
发生这种情况
源代码段:
# self.source should default to being the same as the field name.
if self.source is None:
self.source = field_name
# self.source_attrs is a list of attributes that need to be looked up
# when serializing the instance, or populating the validated data.
if self.source == '*':
self.source_attrs = []
else:
self.source_attrs = self.source.split('.')
最后,使用source
中声明的source_attrs
和bind
获取以下值:
def get_attribute(self, instance):
"""
Given the *outgoing* object instance, return the primitive value
that should be used for this field.
"""
try:
return get_attribute(instance, self.source_attrs)
except (KeyError, AttributeError) as exc:
假设Question
可以有多个Answers
,那么您的方法是正确的。
问题似乎是您提供的源是RelatedManager
实例本身,而不是Answer
对象的查询集。我假设DRF准确地解决了这个问题,您可以尝试将其更改为source =' answer_set.all'。
answer_set
是Django提供的默认RelatedManager
名称。在Django模型中使用related_name命名您的后向关系可能是明智的。这可以通过更改:
question = models.ForeignKey(Question,on_delete=models.PROTECT, related_name='answers')