3
votes

models:

class Questionnaire(models.Model):
    ...

class Question(models.Model):
    ...
    questionnaire = models.ForeignKey('Questionnaire', related_name='questions', blank=True, null=True)
    ...

serializers:

class QuestionSerializer(serializers.ModelSerializer):
    choices = MultipleChoiceSerializer(many=True)
    children = RecursiveField(many=True)

    class Meta:
        model = Question
        fields = [
            'id',
            'text',
            'order',
            'choices',
            #'parent',
            'children',
            'type',
            'category',
            'requiredif',
            'max_answers',
            'min_answers',
        ]

class QuestionnaireCreateUpdateSerializer(serializers.ModelSerializer):
    questions = QuestionSerializer(many=True)

    class Meta:
        model = Questionnaire
        fields = [
            'id',
            'questions',
            'name',
            'description',
        ]

        def create(self, validated_data):
            print validated_data
            ...

validated_data using {'name': 'a', 'description': 'b', 'questions': [{'category': 'a', 'min_answers': 1}]}:

{u'name': u'a', u'questions': [], u'description': u'b'}

simple test:

def test_submit_qnr(self):
        self.client.force_login(self.user.user)
        qnr2 = {'name': 'a', 'description': 'b', 'questions': [{'category': 'a', 'min_answers': 1}]}
        response = self.client.post('/api/qnr/', data=qnr2)
        print response.json()
        response.json()['questions'].should_not.equal([])  # fails!

JSON response:

{u'description': u'b', u'id': 1, u'questions': [], u'name': u'a'}

I would like to write nested fields and have overridden create to do so, but there seems to be an issue with validation, in that the data for the nested models is deleted in the validated_data. I tried printing the validated_data variable at the top of the create function and for reasons I don't understand the questions field is an empty list. The relations section in the api-guide documentation shows almost this exact same example. What am I missing?

EDIT1:

The serializer works as expected when tested directly in the shell, but for some reason it fails in the test case

EDIT 2: View:

class QuestionnaireViewSet(viewsets.ModelViewSet):
    authentication_classes = [SessionAuthentication, BasicAuthentication, JSONWebTokenAuthentication]
    permission_classes = [permissions.IsAuthenticated, ]
    queryset = Questionnaire.objects.all()
    serializer_class = QuestionnaireCreateUpdateSerializer

URLs:

router = routers.DefaultRouter()
router.register(r'qnr', QuestionnaireViewSet)

urlpatterns = [
    ...
    url(r'^api/', include(router.urls)),
    ]
1
Can you also add the QuestionSerializer?AKS
@AKS added the serializerVerbal_Kint
Everything looks alright here. Did you try to do this in console as shown in the api-guide example?AKS
Can you try adding format='json' in your client.post call?AKS

1 Answers

2
votes

Since you followed the example provided in the api-guide and it works in shell I think that the data is not being sent properly.

Django Rest Framework uses APIClient for testing which is based on Django's Test Client

If you don't provide a content type the default value is multipart/form-data

If you don’t provide a value for content_type, the values in data will be transmitted with a content type of multipart/form-data. In this case, the key-value pairs in data will be encoded as a multipart message and used to create the POST data payload.

You will need to explicitly specify the format of the data as json:

response = self.client.post('/api/qnr/', data=qnr2, format='json')