0

I'm trying to upload file via APIView, but I'm getting that exception: {"exception": "ValidationException", "code": 401, "message": "You cannot access body after reading from request's data stream"} Here's my code:

API View:

class SetAvatarView(LoginRequiredAPIView):
    @csrf_exempt  # Does no affect to situation
    def post(self, request):
        try:
            request.account.update_avatar(request.FILES['file'])
        except ValidationException, e:
            return JsonResponse(e.to_dict(), status=400)
        return JsonResponse({}, 200)

Account model:

class Account(models.Model):
    ...
    avatar = models.ImageField(upload_to=AVATARS_URL, default='default.jpg')
    ...
    def update_avatar(self, f):
        self.avatar = f

Test code for uploading file:

def test_set_avatar(self):
    url = "/account/avatar/set/"
    with open("test.jpg", "r") as fp:
        response = self.client.post(url, {'file': fp}, #content_type='multipart/form-data', # Getting 400 Bad Request if uncomment
                                    **{'HTTP_AUTHORIZATION': 'Token 0ff0884090**********8ef5387423bc24cd15e1'})
    print response.content
    self.assertEqual(response.status_code, 200)

No additional middlewares in settings.py, and I tried to disable default middlewares, no result.

Pavel Shishmarev
  • 1,335
  • 9
  • 24
  • i think you need `fp.read()` – Brown Bear Jul 05 '18 at 11:52
  • If send file like `{'file': fp.read()}` I receive `{"error": "HTTP Status 415 - Unsupported Media Type"} ` – Pavel Shishmarev Jul 05 '18 at 12:10
  • And if send like that and add content-type: image/jpeg, so error is `Expecting property name: line 1 column 2 (char 1)` – Pavel Shishmarev Jul 05 '18 at 12:14
  • try to add `format='multipart'` from here https://stackoverflow.com/a/27576436/8060120 – Brown Bear Jul 05 '18 at 12:14
  • `format='multipart` with content-type and fp.read() doesn't affect at all – Pavel Shishmarev Jul 05 '18 at 12:16
  • did you try others answer in the link? – Brown Bear Jul 05 '18 at 12:19
  • Maybe I found a solution, but there are strange exception ``` response = self.client.post(url, data=encode_multipart(BOUNDARY, {'file': fp}), **{'HTTP_AUTHORIZATION': 'Token 0ff08840935eb00fad198ef5387423bc24cd15e1'}) ``` ``` line 197, in encode_multipart for (key, value) in data.items(): AttributeError: 'str' object has no attribute 'items' ``` `data` is a dict(`{'file': fp }`) but there is an error saying that data has no "items" method – Pavel Shishmarev Jul 05 '18 at 12:29

1 Answers1

0

You have to encode the file and decode in the view /account/avatar/set

import base64 
def test_set_avatar(self):
    url = "/account/avatar/set/"
    with open("test.jpg", "r") as fp:
    response = self.client.post(url, {'file': base64.b64encode(fp.read())}, #content_type='multipart/form-data', # Getting 400 Bad Request if uncomment
                                **{'HTTP_AUTHORIZATION': 'Token 0ff0884090**********8ef5387423bc24cd15e1'})
    print response.content
    self.assertEqual(response.status_code, 200)
  • But actually it does not solve the original problem. Yes, you can send file as base64-encoded string, but what if you're going to use this endpoint in HTML form or public API and want to just receive file? – Pavel Shishmarev Jun 12 '20 at 13:45