15

Edit: I've tried everything in this question and it doesn't solve the issue. Meaning I tried I tried manually adding FormParser and MultiPartParser to DEFAULT_PARSER_CLASSES in settings, and I've tried changing django.test.TestCase to rest_framework.test.APITestCase. I still get the same error code.

When I send a PATCH request to my Django app running on localhost via the command line like so:

http -a <username>:<password> PATCH http://127.0.0.1:8000/post/1/ text="new text"

It works as expected and I get a 200 OK code back.

When I try to do the same thing in my unit test using the django.test.Client.patch method like this:

In [1]: from django.test import Client
In [2]: client = Client()
In [3]: client.login(username='<username>', password='<password>')
Out[3]: True
In [4]: client.patch('/post/1/', {'text': 'new text'})
Out[4]: <Response status_code=415, "application/json">

I get a 415 (Unsupported Media) response code. The response.data is Unsupported media type "application/octet-stream" in request.'

If I try adding the parameter content-type='application/json' to the patch method (I shouldn't have to do this because I'm able to send GET, POST, and DELETE requests using the Client class without providing that parameter) I get a 400 error code. and the response.data is 'JSON parse error - Expecting property name enclosed in double quotes: line 1 column 2 (char 1)'

As I said, when I use the class's get, delete, and post methods, the behavior is as expected.

Am I using the method properly? Is this a bug?

Matt
  • 2,232
  • 8
  • 35
  • 64
  • 1
    Possible duplicate of [django-rest-framework http put failing with 415 on django 1.5](https://stackoverflow.com/questions/15153048/django-rest-framework-http-put-failing-with-415-on-django-1-5) – Linch Jun 17 '17 at 20:20
  • @Linch that doesn't solve it. – Matt Jun 17 '17 at 20:48
  • Have you tried encoding the dictionary as json as the related question suggests, i.e. `client.patch('/post/1/', json.dumps({'text': 'new text'}), content_type="application/json")`? – Alasdair Jun 17 '17 at 20:57

2 Answers2

27

As far as I know, httpie sends a request with the content-type application/json.

So, try this:

import json 
data = json.dumps({'text': 'new text'})

client.patch('/post/1/', data, content_type='application/json')
Linch
  • 511
  • 4
  • 11
  • This works for me too, but it's a bit manual as a global solution to have to dump data for every test and also specify `content_type` for every test. Is there a more global solution that you know of? Thanks! – jordancooperman Apr 10 '19 at 20:49
  • Actually, it looks like you can set this globally in settings with `'TEST_REQUEST_DEFAULT_FORMAT': 'json'` as per docs: https://www.django-rest-framework.org/api-guide/testing/#configuration – jordancooperman Apr 10 '19 at 21:32
  • 1
    I have no clue why for POST you can miss content_type without getting a 415... – Alex M.M. Oct 26 '20 at 13:47
0

As for why you need to add a content_type for PATCH (and PUT, OPTIONS, DELETE). It's because Django uses different defaults for content_type. For post it uses multipart/form-data while for the others it uses application/octet-stream. Not 100% sure why, but that explains the POST/GET succeeding

Barry the Platipus
  • 9,594
  • 2
  • 6
  • 30