DRF ListSerializer Error: Expected a list of items but got type "int"
DRF ListSerializer Error: Expected a list of items but got type "int"
我试图通过将 many=True
传递给序列化程序来序列化对象列表。如果我传递一个实例而不是一个没有 many=True
的列表,序列化程序就可以工作。我仍在尝试了解序列化器的工作原理,但无法调试此问题。我正在使用 DRF 3.3.0
查看:(下面第 3 行错误)
class BubbleExamView(object):
def get_context_data(self, **kwargs):
sections = self.data.exam.section_set.all()
if serializers.TakeSectionSerializer(
sections, self.data.user.id, many=True).is_valid(raise_exception=True):
sections_json = renderer.render(serializers.TakeSectionSerializer(
sections, self.data.user.id, many=True).data)
context = {
'exam': self.data.exam,
'sections_json': sections_json,
'student': self.data.user,
'course': self.data.exam.course,
}
context.update(kwargs)
return super(BubbleExamView, self).get_context_data(**context)
....
....
序列化器:
class FullAssetSerializer(serializers.ModelSerializer):
image = serializers.SerializerMethodField('get_image_url')
def get_image_url(self, asset):
if asset.image:
return default_storage.url(asset.image.name)
class Meta:
model = models.Asset
fields = ('id', 'asset_type', 'text', 'image',)
class FullQuestionAssetSerializer(serializers.ModelSerializer):
asset = FullAssetSerializer()
class Meta:
model = models.QuestionAsset
fields = ('id', 'order', 'asset')
class StubbedSectionSerializer(serializers.ModelSerializer):
"""Serialize a section object, without any of the assets or questions"""
class Meta:
model = models.Section
fields = ('id', 'exam', 'name', 'number', 'duration', 'break_duration')
class TakeSectionSerializer(StubbedSectionSerializer):
"""Serialize a section object, along with all the assets and questions that are contained in the section
in order to display it to a student taking the exam"""
class Meta(StubbedSectionSerializer.Meta):
fields = StubbedSectionSerializer.Meta.fields + ('assets', 'examquestions')
examquestions = serializers.SerializerMethodField('get_exam_questions')
assets = FullAssetSerializer(many=True)
def __init__(self, section, user_id, **kwargs):
super(TakeSectionSerializer, self).__init__(section, **kwargs)
self.user_id = user_id
def get_exam_questions(self, section):
examquestions = section.examquestion_set.all()
kwargs = {
'exam_question__section_id':section.id,
'exam_response__user_id':self.user_id,
}
choiceresponses = models.ChoiceQuestionResponse.objects.filter(**kwargs)
textresponses = models.TextQuestionResponse.objects.filter(**kwargs)
for eq, response in utils.zip_responses(
examquestions,
itertools.chain(choiceresponses, textresponses),
'exam_question_id'
):
eq.response = response
return ExamQuestionSerializer(examquestions, many=True).data
回溯
Traceback:
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
132. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/utils/decorators.py" in inner
145. return func(*args, **kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/views/generic/base.py" in view
71. return self.dispatch(request, *args, **kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapper
34. return bound_func(*args, **kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
22. return view_func(request, *args, **kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/utils/decorators.py" in bound_func
30. return func.__get__(self, type(self))(*args2, **kwargs2)
File "/vagrant/Devel/chalktalk-legacy/chalktalk/chalktalk/shared/view_utils.py" in dispatch
21. return super(CheckPermissionsMixin, self).dispatch(request, *args, **kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/views/generic/base.py" in dispatch
89. return handler(request, *args, **kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/views/generic/base.py" in get
158. context = self.get_context_data(**kwargs)
File "/vagrant/Devel/chalktalk-legacy/chalktalk/chalktalk/apps/exams_sat/views_take.py" in get_context_data
508. sections, self.data.user.id, many=True).is_valid(raise_exception=True):
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/rest_framework/serializers.py" in is_valid
221. raise ValidationError(self.errors)
Exception Type: ValidationError at /sat/474/208/bubble/
Exception Value: {u'non_field_errors': [u'Expected a list of items but got type "int".']}
您只是将用户 ID 作为数据传递给序列化程序,而序列化程序抱怨说这绝对不是正确的数据格式。
if serializers.TakeSectionSerializer(
sections, self.data.user.id, many=True).is_valid(raise_exception=True):
序列化器需要一个完整的数据字典(键是序列化器字段),如果您指定 many=True
,它们需要一个字典列表。您只传递一个值,即用户 ID,而不是字典列表。正因为如此,DRF 抱怨它只得到了一个整数而不是一个项目列表。
我建议 looking at the DRF tutorial 以更好地理解序列化的工作原理。
我不会以此为荣,但这是有效的答案,并且 DRF 人员在他们的 github 问题中回答了这个问题。
"我检查了 DRF 中的 Serializer 代码,我们正在覆盖 __new__
这意味着您的 __init__
构造函数覆盖是无用的(魔术发生在此之前)。这是DRF源代码中的那行代码
我建议您删除 TakeSectionSerializer 中的 __init__
。相反,您应该在上下文 TakeSectionSerializer(sections, context={'user_id': self.user.id}, many=True)
中传递 self.user.id 并相应地修改您的 TakeSectionSerializer 代码。
如果您不知道如何获取上下文以便在 get_exam_questions 中使用它,您可能需要查看我们的 "Including extra context" 示例。基本上 self.context['user_id']
应该可以。
那肯定会解决你的问题。"
我试图通过将 many=True
传递给序列化程序来序列化对象列表。如果我传递一个实例而不是一个没有 many=True
的列表,序列化程序就可以工作。我仍在尝试了解序列化器的工作原理,但无法调试此问题。我正在使用 DRF 3.3.0
查看:(下面第 3 行错误)
class BubbleExamView(object):
def get_context_data(self, **kwargs):
sections = self.data.exam.section_set.all()
if serializers.TakeSectionSerializer(
sections, self.data.user.id, many=True).is_valid(raise_exception=True):
sections_json = renderer.render(serializers.TakeSectionSerializer(
sections, self.data.user.id, many=True).data)
context = {
'exam': self.data.exam,
'sections_json': sections_json,
'student': self.data.user,
'course': self.data.exam.course,
}
context.update(kwargs)
return super(BubbleExamView, self).get_context_data(**context)
....
....
序列化器:
class FullAssetSerializer(serializers.ModelSerializer):
image = serializers.SerializerMethodField('get_image_url')
def get_image_url(self, asset):
if asset.image:
return default_storage.url(asset.image.name)
class Meta:
model = models.Asset
fields = ('id', 'asset_type', 'text', 'image',)
class FullQuestionAssetSerializer(serializers.ModelSerializer):
asset = FullAssetSerializer()
class Meta:
model = models.QuestionAsset
fields = ('id', 'order', 'asset')
class StubbedSectionSerializer(serializers.ModelSerializer):
"""Serialize a section object, without any of the assets or questions"""
class Meta:
model = models.Section
fields = ('id', 'exam', 'name', 'number', 'duration', 'break_duration')
class TakeSectionSerializer(StubbedSectionSerializer):
"""Serialize a section object, along with all the assets and questions that are contained in the section
in order to display it to a student taking the exam"""
class Meta(StubbedSectionSerializer.Meta):
fields = StubbedSectionSerializer.Meta.fields + ('assets', 'examquestions')
examquestions = serializers.SerializerMethodField('get_exam_questions')
assets = FullAssetSerializer(many=True)
def __init__(self, section, user_id, **kwargs):
super(TakeSectionSerializer, self).__init__(section, **kwargs)
self.user_id = user_id
def get_exam_questions(self, section):
examquestions = section.examquestion_set.all()
kwargs = {
'exam_question__section_id':section.id,
'exam_response__user_id':self.user_id,
}
choiceresponses = models.ChoiceQuestionResponse.objects.filter(**kwargs)
textresponses = models.TextQuestionResponse.objects.filter(**kwargs)
for eq, response in utils.zip_responses(
examquestions,
itertools.chain(choiceresponses, textresponses),
'exam_question_id'
):
eq.response = response
return ExamQuestionSerializer(examquestions, many=True).data
回溯
Traceback:
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
132. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/utils/decorators.py" in inner
145. return func(*args, **kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/views/generic/base.py" in view
71. return self.dispatch(request, *args, **kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapper
34. return bound_func(*args, **kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
22. return view_func(request, *args, **kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/utils/decorators.py" in bound_func
30. return func.__get__(self, type(self))(*args2, **kwargs2)
File "/vagrant/Devel/chalktalk-legacy/chalktalk/chalktalk/shared/view_utils.py" in dispatch
21. return super(CheckPermissionsMixin, self).dispatch(request, *args, **kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/views/generic/base.py" in dispatch
89. return handler(request, *args, **kwargs)
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/django/views/generic/base.py" in get
158. context = self.get_context_data(**kwargs)
File "/vagrant/Devel/chalktalk-legacy/chalktalk/chalktalk/apps/exams_sat/views_take.py" in get_context_data
508. sections, self.data.user.id, many=True).is_valid(raise_exception=True):
File "/home/vagrant/.virtualenvs/chalktalk-legacy/local/lib/python2.7/site-packages/rest_framework/serializers.py" in is_valid
221. raise ValidationError(self.errors)
Exception Type: ValidationError at /sat/474/208/bubble/
Exception Value: {u'non_field_errors': [u'Expected a list of items but got type "int".']}
您只是将用户 ID 作为数据传递给序列化程序,而序列化程序抱怨说这绝对不是正确的数据格式。
if serializers.TakeSectionSerializer(
sections, self.data.user.id, many=True).is_valid(raise_exception=True):
序列化器需要一个完整的数据字典(键是序列化器字段),如果您指定 many=True
,它们需要一个字典列表。您只传递一个值,即用户 ID,而不是字典列表。正因为如此,DRF 抱怨它只得到了一个整数而不是一个项目列表。
我建议 looking at the DRF tutorial 以更好地理解序列化的工作原理。
我不会以此为荣,但这是有效的答案,并且 DRF 人员在他们的 github 问题中回答了这个问题。
"我检查了 DRF 中的 Serializer 代码,我们正在覆盖 __new__
这意味着您的 __init__
构造函数覆盖是无用的(魔术发生在此之前)。这是DRF源代码中的那行代码
我建议您删除 TakeSectionSerializer 中的 __init__
。相反,您应该在上下文 TakeSectionSerializer(sections, context={'user_id': self.user.id}, many=True)
中传递 self.user.id 并相应地修改您的 TakeSectionSerializer 代码。
如果您不知道如何获取上下文以便在 get_exam_questions 中使用它,您可能需要查看我们的 "Including extra context" 示例。基本上 self.context['user_id']
应该可以。
那肯定会解决你的问题。"