Search code examples
djangodjango-testing

Django Test Client sends values as a list instead of strings


I have a problem, I am not sure whether I had overlooked something, or simply doing something wrong. I am trying to test an endpoint that allows a user to register.

My model:

class Account(User):
    objects = UserManager()
    balance = models.FloatField(blank=True, default=0)
    rank_position = models.IntegerField(blank=True, null=True)
    rank_title = models.CharField(max_length=255, blank=True, default="Novice")

Serializer:

class AccountSerializer(ModelSerializer):
    class Meta:
        model = Account
        fields = '__all__

View:

@api_view(['POST'])
def register(request):
    try:
        acc = Account.objects.create(**request.POST)
        acc_srl = AccountSerializer(acc)
        return Response(data=acc_srl.data, status=status.HTTP_201_CREATED)
    except Exception as e:
        return Response(status=status.HTTP_400_BAD_REQUEST)

And I am trying to use a Django test client in a following way:

class TestAuthentication(TestCase):
    def setUp(self):
        self.c = Client()

    def test_register(self):
        data = {'username': 'test_user', 'password': '1234'}
        response = self.c.post('/api/register/', data)
        print(response.json())
        self.assertEqual(response.status_code, 201)
        acc = Account.objects.get(username="test_user")
        self.assertEqual(acc.username, "test_user")
        self.assertTrue(isinstance(acc, User))

The function works as expected, but a strange thing happens. When I inspect request.POST both username and password are a list as so:

<QueryDict: {'username': ['test_user'], 'password': ['1234']}>

I am puzzled as I dont understand what causes this behavior.


Solution

  • This is a function built-in to Django to handle multiple values with the same key. See docs.

    And when you are using Django's test client this.c.post and send data in the second parameter. Then Django will send that as URL parameters and not a POST body.

    So your request will look like: '/api/register/?username=test_user&password=1234'

    Let's say you send a request with '/api/register/?username=test_user&password=1234&password=5486' Then your request.POST would look like:

    <QueryDict: {'username': ['test_user'], 'password': ['1234', '5486']}>
    

    So, I don't think you have to worry about this.