【问题标题】:Django Test Client sends values as a list instead of stringsDjango Test Client 将值作为列表而不是字符串发送
【发布时间】:2021-11-30 22:50:50
【问题描述】:

我有一个问题,我不确定我是否忽略了什么,或者只是做错了什么。我正在尝试测试一个允许用户注册的端点。

我的模特:

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

序列化器:

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 django-testing


    【解决方案1】:

    这是 Django 内置的一个函数,用于处理具有相同键的多个值。见docs

    而当你使用 Django 的测试客户端this.c.post 并在第二个参数中发送数据时。然后 Django 会将其作为 URL 参数而不是 POST 正文发送。

    所以您的请求将如下所示:'/api/register/?username=test_user&amp;password=1234'

    假设您使用'/api/register/?username=test_user&amp;password=1234&amp;password=5486' 发送请求 然后你的request.POST 看起来像:

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

    所以,我认为你不必担心这个。

    【讨论】:

    • 感谢大家的回复。我现在明白了。
    【解决方案2】:

    如 Django 文档中所述:

    在 HttpRequest 对象中,GET 和 POST 属性是 django.http.QueryDict,一个类字典类自定义处理 多个值用于同一个键。

    然后,如果您想访问这些项目,请使用QueryDict.__getitem__ 方法:

    所以,在你的情况下,它会是这样的:

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

    或者如果查询参数上有多个值,可以使用QueryDict.getlist

    >>> POST = QueryDict('user_ids=ID1&user_ids=ID2&user_ids=ID3&')
    >>> POST.getlist('user_ids')
    ['ID1', 'ID2', 'ID3']
    

    查询字典: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

    【讨论】:

      【解决方案3】:

      我认为这是request.POST 的正常行为。正如您可以为同一参数执行多个值的POST:例如:/api/register/?username=user&amp;username=admin,因此您将拥有

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

      您可以在官方文档中查看:https://docs.djangoproject.com/en/3.2/ref/request-response/#django.http.QueryDict

      【讨论】:

        猜你喜欢
        • 2017-09-22
        • 1970-01-01
        • 2014-11-02
        • 2020-06-02
        • 2021-10-13
        • 1970-01-01
        • 1970-01-01
        • 2018-07-21
        • 2023-01-22
        相关资源
        最近更新 更多