Verbal_Kint
Verbal_Kint

Reputation: 1416

Django rest framework reverse relation field data omitted from validated_data

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)),
    ]

Upvotes: 3

Views: 657

Answers (1)

AKS
AKS

Reputation: 19811

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')

Upvotes: 2

Related Questions