【问题标题】:PATCH and PUT don't work as expected when pytest is interacting with REST framework当 pytest 与 REST 框架交互时,PATCH 和 PUT 无法按预期工作
【发布时间】:2017-02-15 20:18:03
【问题描述】:

我正在使用 django REST 框架构建一个 API。

为了测试这个 API,我使用 pytest 和测试客户端,如下所示:

def test_doesnt_find(self, client):
    resp = client.post(self.url, data={'name': '123'})
    assert resp.status_code == 404

def test_doesnt_find(self, client):
    resp = client.get(self.url, data={'name': '123'})
    assert resp.status_code == 404

在使用 REST 框架的通用 GET、POST 和 DELETE 类(如 DestroyAPIViewRetrieveUpdateAPIView 或仅使用 get 和 post 函数的 APIView)时,两者都可以工作

我遇到问题的地方是使用 PATCH 和 PUT 视图时。如RetrieveUpdateAPIView。这里突然不得不用:

resp = client.patch(self.url, data="name=123", content_type='application/x-www-form-urlencoded')

resp = client.patch(self.url, data=json.dumps({'name': '123'}), content_type='application/json')

如果我只是像以前一样尝试使用测试客户端,我会收到错误:

rest_framework.exceptions.UnsupportedMediaType: Unsupported media type "application/octet-stream" in request.

当我在 client.patch() 调用中指定 'application/json' 时:

rest_framework.exceptions.ParseError: JSON parse error - Expecting property name enclosed in double quotes: line 1 column 2 (char 1)`

谁能向我解释这种行为?使用 -X PATCH -d"name=123" 时,curl 也能正常工作。

【问题讨论】:

标签: python django-rest-framework put pytest-django


【解决方案1】:

Pytest 使用 django 测试客户端,client.post 默认 content_type 是 multipart/form-data,而 putpatchdelete 使用 application/octet-stream .

这就是为什么有时这很棘手。即使是发布请求,如果您计划支持 JSON 有效负载,您必须在测试请求中告知内容类型。无论如何,对于最近的 Django 版本,您只需将数据对象传递给客户端请求,它将为您序列化,如 docs 中所述:

如果您提供 content_type 为 application/json,则数据为 如果它是字典、列表或元组,则使用 json.dumps() 进行序列化。 序列化默认使用 DjangoJSONEncoder 进行,并且可以 通过向客户端提供 json_encoder 参数来覆盖。这 put()、patch() 和 delete() 请求也会发生序列化。

例如:

resp = client.patch(self.url, {'name': '123'}, content_type='application/json')

【讨论】:

    【解决方案2】:

    rest_framework.exceptions.ParseError:JSON 解析错误 - 期望用双引号括起来的属性名称:第 1 行第 2 列(字符 1)`

    这通常表明您在 json 中的字符串中发送了一个字符串。 例如:

    resp = client.patch(self.url, data=json.dumps("name=123"), content_type='application/json')
    

    会导致此类问题。

    rest_framework.exceptions.UnsupportedMediaType:请求中不支持的媒体类型“application/octet-stream”。

    这意味着请求已作为“application/octet-stream”发送,这是 Django 的测试默认设置。

    为了减轻处理这一切的痛苦,Django REST 框架自己提供了一个客户端:http://www.django-rest-framework.org/api-guide/testing/#apiclient

    请注意,该语法与 Django 的语法略有不同,您不必处理 json 编码。

    【讨论】:

    • 提示:您可以从 APITestCase 继承您的测试类,而不是实例化 APIClient
    • resp = client.patch(self.url, json={"name": 123})
    【解决方案3】:

    对于带有 JSON 数据的请求,您收到此错误是因为 JSON syntax 它需要在字符串上使用 双引号

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-10
      • 2015-05-03
      • 2018-01-08
      • 2023-03-14
      • 1970-01-01
      • 2013-11-30
      相关资源
      最近更新 更多