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'] 应该可以。 那肯定会解决你的问题。"