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

I won't take credit for this, but this is the answer that worked and was answered by the DRF folks in their github issues.

"I checked the Serializer code inside DRF, and we are overriding __new__ which means your __init__ constructor override is useless (the magic happens before that). Here is that line of code in the DRF source I would suggest you to remove __init__ inside TakeSectionSerializer. Instead you should pass the self.user.id inside a context TakeSectionSerializer(sections, context={'user_id': self.user.id}, many=True) and modify your TakeSectionSerializer code accordingly.

If you don't know how to get the context so you can use it in your get_exam_questions, you may want to check out our "Including extra context" example. Basically self.context['user_id'] should work. That will definitely take care of your problem."

于 2015-11-28T18:33:04.567 に答える