Тестовый клиент Django отправляет значения в виде списка вместо строк

У меня проблема, я не уверен, упустил ли я что-то из виду, или просто делаю что-то неправильно. Я пытаюсь протестировать конечную точку, которая позволяет пользователю зарегистрироваться.

Моя модель:

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__

Вид:

@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)

Я пытаюсь использовать тестовый клиент Django следующим образом:

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))

Функция работает как ожидалось, но происходит странная вещь. Когда я проверяю request.POST и имя пользователя, и пароль представляют собой список, как показано ниже:

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

Я в недоумении, поскольку не понимаю, что вызывает такое поведение.

Это встроенная в Django функция для обработки нескольких значений с одним и тем же ключом. См. docs.

Когда вы используете тестовый клиент Django this.c.post и отправляете данные во втором параметре. Тогда Django отправит их как параметры URL, а не как тело POST.

Таким образом, ваш запрос будет выглядеть следующим образом: '/api/register/?username=test_user&password=1234'

Допустим, вы отправляете запрос с помощью '/api/register/?username=test_user&password=1234&password=5486'. Тогда ваш request.POST будет выглядеть так:

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

Так что, я думаю, вам не стоит беспокоиться об этом.

Я думаю, что это нормальное поведение request.POST. Поскольку вы можете сделать POST с несколькими значениями для одного и того же параметра: Например: /api/register/?username=user&username=admin, тогда у вас будет

<QueryDict: {'username': ['user', 'admin']}>

Вы можете проверить это в официальной документации: https://docs.djangoproject.com/en/3.2/ref/request-response/#django.http.QueryDict

Как упоминается в документации Django:

В объекте HttpRequest атрибуты GET и POST являются экземплярами django.http.QueryDict, словареподобный класс, настроенный для работы с множественными значениями для одного и того же ключа.

Затем, если вы хотите получить доступ к этим элементам, используйте метод QueryDict.__getitem__:

Итак, в вашем случае это было бы что-то вроде:

>>> request.POST['username']
test_user
>>> request.POST['password']
1234

Или если у вас несколько значений в queryparams, вы можете использовать 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

Вернуться на верх