5

I am using djangorestframework==3.3.3 and Django==1.9.4

I have a test where I want to check that query parameters processed correctly.

class TestResourceView(APITestCase):

    def test_view_process_query_params_correctly(self):
        client = APIClient()
        client.login(username='<username>', password='password')
        response = client.get('/api/v2/resource/1/users/?fields=first_name;last_name')
        self.assertEqual(response.status_code, 200)
        # .... rest of the test .... 

In my view I put print statement just to see if query parameters are parsed properly, but I get empty query dictionary:

class Resource(APIView):
    def get(self, request):
        query_params = request.query_params
        print('Printing query params')
        print(query_params)
        # .... rest of the code ....

    def post(self, request):
        query_params = request.query_params
        print('Printing query params')
        print(query_params)
        # .... rest of the code ....

Result in terminal when running tests:

Printing query params
<QueryDict: {}>

In the same time if I test post request like this:

response = client.post('/api/v2/resource/1/users/?fields=first_name;last_name')

i get params incorrectly parsed:

Printing query params
<QueryDict: {'last_name': [''], 'fields': ['first_name']}>

What is the correct way of using APIClient? Or is this still a bug? Because there was already similar issue

AmirM
  • 1,089
  • 1
  • 12
  • 26

3 Answers3

1

For me, the issue was that DRF wants the params in data not args like the Django test client.

This answer helped me: https://stackoverflow.com/a/45183972/9512437

class AccountTests(APITestCase):

    def setUp(self):
        self.user = CustomUser.objects.create_user(email="user1@test.com", password="password1", is_staff=True)
        self.client = APIClient()

    def test_add_name(self):
        self.client.force_authenticate(self.user)

        url = reverse('customuser-detail', args=(self.user.id,))
        data = {'first_name': 'test', 'last_name': 'user'}
        response = self.client.put(url, data, format='json')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
Marc LaBelle
  • 270
  • 5
  • 12
  • 2
    I believe you might have misunderstood the question; it's asking about `query_params` not request data – Mitch May 27 '20 at 16:36
0

The format of your query parameters is incorrect.

If you want the result to be {'fields': ['last_name', 'first_name']}, then your POST url should be .../users/?fields=first_name&fields=last_name'. You'll probably want to access the params using getlist().

camden
  • 1,908
  • 19
  • 18
  • The idea is to get query params, and parse them the way I need. For example, there might be params like this `/api/v2/resource/1/users/?fields=first_name;last_name`, which will be parsed into the set `{'first_name', 'last_name'}`. One more option `/api/v2/resource/1/users/?fields=1-4`, which under the hood will be parsed into the set `{'first_name', 'last_name', 'phone', 'skype'}`. And still, another problem remains `client.get('/api/v2/resource/1/users/?fields=first_name;last_name')` results in empty `query_params` – AmirM Jul 15 '16 at 08:36
0

1) Regarding empty <QueryDict: {}> in client.get('/api/v2/resource/1/users/?fields=first_name;last_name') - there was my mistake in my code. I had two tests with the same name, one of which indeed has empty <QueryDict: {}>. So, when running tests, django ran the test with <QueryDict: {}>

2) Regarding incorrect parsing of query params in client.post('/api/v2/resource/1/users/?fields=first_name;last_name'), I found the following discussion. So, django basically follows HTTP standards, where it is said that ; semicolon is reserved character and if using, than the correct way to comprehend it same as &. Here more details

AmirM
  • 1,089
  • 1
  • 12
  • 26