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.
CodePudding user response:
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.
CodePudding user response:
As mentioned in Django's doc:
In an HttpRequest object, the GET and POST attributes are instances of django.http.QueryDict, a dictionary-like class customized to deal with multiple values for the same key.
Then, if you want to access those items, use QueryDict.__getitem__
method:
So, in your case, it would be something like:
>>> request.POST['username']
test_user
>>> request.POST['password']
1234
Or if you have multiple values on the queryparams, you can use QueryDict.getlist
:
>>> POST = QueryDict('user_ids=ID1&user_ids=ID2&user_ids=ID3&')
>>> POST.getlist('user_ids')
['ID1', 'ID2', 'ID3']
QueryDict: https://docs.djangoproject.com/en/3.1/ref/request-response/#querydict-objects
QueryDict.__getitem__: https://docs.djangoproject.com/en/3.1/ref/request-response/#django.http.QueryDict.\_\_getitem\_\_
QueryDict.getlist: https://docs.djangoproject.com/en/3.1/ref/request-response/#django.http.QueryDict.getlist
CodePudding user response:
I think that's the normal behavior of the request.POST
. As you can do a POST
with multiple values for the same parameter: Eg: /api/register/?username=user&username=admin
, so you will have
<QueryDict: {'username': ['user', 'admin']}>
You can check this in the official doc: https://docs.djangoproject.com/en/3.2/ref/request-response/#django.http.QueryDict