Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#30840 closed Bug (invalid)

Sending JSON using the django test client fails when providing content_type='application/json'

Reported by: Fernando Cordeiro Owned by: nobody
Component: Testing framework Version: 2.2
Severity: Normal Keywords: ajax
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Given the following statement from the docs (https://docs.djangoproject.com/en/2.2/topics/testing/tools/#django.test.Client.post):

If you provide content_type as application/json, the data is serialized using json.dumps() if it’s a dict, list, or tuple.

I created the following TestCase in order to test if my AJAX POST request could update my model correctly:

class MyUpdateViewTest(TestCase):

    def test_update_model_field(self):
        self.client.force_login(self.user)
        url = reverse('MyModel_update', args=[pk])
        resp = self.client.post(
            url,
            data={'field' : 4},
            content_type='application/json',
            HTTP_X_REQUESTED_WITH='XMLHttpRequest'
        )
        obj = MyModel.objects.filter(...)
        self.assertEqual(obj[0].field, 4)

The corresponding view:

class MyUpdateView(UpdateView):
    """Updates a MyModel via its pk with AJAX form data"""
    model = MyModel
    form_class = MyModelForm

    def form_valid(self, form):
        self.object = form.save()
        data = {'pk': self.object.pk}
        return JsonResponse(data)

    def form_invalid(self, form):
        return JsonResponse(form.errors, status=400)

    def post(self, request, *args, **kwargs):
        if request.is_ajax():
            return super().post(self, request, *args, **kwargs)
        else:
            return HttpResponseBadRequest()

What happened was that whenever I added content_type='application/json', the view never received any data at all (i.e. request.POST was an empty queryset) which then made the form.is_valid() method fail and return a form field error. I tried this with and without ´json.dumps()` on the POST data.

However, as soon as I removed the content_type='application/json' parameter, the test worked! So, given the docs, I believe a bug is afoot.

This problem only happened during testing.

Change History (3)

comment:1 by Fernando Cordeiro, 5 years ago

Type: UncategorizedBug

comment:2 by Claude Paroz, 5 years ago

Resolution: invalid
Status: newclosed

That's expected behavior. A Django request knows how to handle 'multipart/form-data' or 'application/x-www-form-urlencoded' to populate the request.POST dict. But if you use any other content type, it's your duty to handle the request body and implement a custom content parsing.

in reply to:  2 comment:3 by Fernando Cordeiro, 5 years ago

Replying to Claude Paroz:

That's expected behavior. A Django request knows how to handle 'multipart/form-data' or 'application/x-www-form-urlencoded' to populate the request.POST dict. But if you use any other content type, it's your duty to handle the request body and implement a custom content parsing.

I'm sorry. Given what was stated in the aforementioned documentation and what the method django.client.test.RequestFactory._encode_json does, I was under the impression just using a 'application/json' content_type and having my data as a dict would be enough for Django to correctly parse its content during testing.

Note: See TracTickets for help on using tickets.
Back to Top