0

我正在尝试通过传递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".']}
4

2 回答 2

2

您只是将用户 ID 作为数据传递给序列化程序,而序列化程序正在抱怨,因为这绝对不是正确的数据格式。

if serializers.TakeSectionSerializer(
       sections, self.data.user.id, many=True).is_valid(raise_exception=True):

序列化器需要一个完整的数据字典(键是序列化器字段),如果您指定many=True. 您只传入一个值,即用户的 id,而不是字典列表。因此,DRF 抱怨它只给出了一个整数而不是一个项目列表。

我建议查看 DRF 教程,以更好地了解序列化的工作原理。

于 2015-11-28T02:48:14.803 回答
0

我不会对此表示赞赏,但这是有效的答案,并且 DRF 人员在他们的 github 问题中得到了回答。

我检查了 DRF 中的 Serializer 代码,我们正在覆盖__new__,这意味着你的__init__构造函数覆盖是无用的(在那之前发生了魔法)。这是 DRF 源代码中的那行代码,我建议你__init__在 TakeSectionSerializer 中删除。相反,你应该在上下文中传递 self.user.idTakeSectionSerializer(sections, context={'user_id': self.user.id}, many=True)并相应地修改您的 TakeSectionSerializer 代码。

如果您不知道如何获取上下文以便在 get_exam_questions 中使用它,您可能需要查看我们的“包含额外上下文”示例。基本上self.context['user_id']应该可以工作。那肯定会解决您的问题。"

于 2015-11-28T18:33:04.567 回答