20

I am trying to use bulk update from drf-extensions. To make it work, there is a safeguard requiring the header "X-BULK-OPERATION": 'true'. I can get the application working using curl or my angular app, but in my tests I am trying to use rest_framework.test.APIClient to send the partial_update request, but every time I get a 400 response, and when debugging the request, I am getting

ipdb> response.data
{'detail': "Header 'X-BULK-OPERATION' should be provided for bulk operation."}

This is the request I am trying to use in my test

    response = self.client.patch(
        '/api/v1/db_items/?active=True',
        json.dumps(data),
        content_type='application/json',
        **{X-BULK-OPERATION: 'true'}
    )

Is there a way to set headers on an APIClient request?

I've even tried changing the header name and setting it in credentials with

self.client.credentials(HTTP_BULK_OPERATION='true')

but I get the same error every single time

Murphy4
  • 1,499
  • 2
  • 15
  • 22

4 Answers4

38

The answer is extremely poorly documented, but it seems django does its own parsing of the headers passed in. I successfully did this by changing my code to be

response = self.client.patch(
    "/api/v1/db_items/?active=True",
    json.dumps(data),
    content_type="application/json",
    HTTP_X_BULK_OPERATION="true",
)

Note the HTTP_ prefix. This is recognized by the Django client and translated to a HTTP header with the key X-BULK-OPERATION and the value "true"

Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
Murphy4
  • 1,499
  • 2
  • 15
  • 22
  • 3
    Thank you for your answer. Very helpful. A note on the documentation, DRF states their API Client extends the Django Client where they link to it's docs. It is there, Django explains adding headers with a HTTP_ prefix. I didn't notice it the first time while struggling with this very thing. – NathanQ Jun 13 '22 at 22:18
10

Your initial solution is almost correct; you are just missing the "X" portion of your header field name:

self.client.credentials(HTTP_X_BULK_OPERATION='true')

This worked for me with other arbitrary header keys.

user141720
  • 101
  • 1
  • 2
8

Or you can just pass it as a kwarg of request.
It is important to add HTTP_ prefix to your header (HTTP_MyHeader, instead of MyHeader):

response = self.client.patch(
    '/api/v1/db_items/?active=True',
    json.dumps(data),
    content_type='application/json',
    'HTTP_X_BULK_OPERATION'='true'
)
סטנלי גרונן
  • 2,917
  • 23
  • 46
  • 68
Raff
  • 139
  • 2
  • 4
3

if you'r using standard header like HTTP_ACCEPT(Accept header) or HTTP_AUTHORIZATION (AUTHORIZATION header) you can also use these two ways

DRF doc recommends first way and if you want to apply header to all request use first way

1-

client.credentials(HTTP_ACCEPT='application/json; version=1.0')

response = self.client.patch(
        '/api/v1/db_items/?active=True',
        json.dumps(data),
        content_type='application/json'
    )

2-

response = self.client.patch(
    '/api/v1/db_items/?active=True',
     json.dumps(data),
     content_type='application/json',
     HTTP_ACCEPT='application/json; version=1.0'
    )