当 pytest 与 REST 框架交互时,PATCH 和 PUT 无法按预期工作

问题描述 投票:0回答:5

我正在使用 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 类时都可以工作(例如

DestroyAPIView
RetrieveUpdateAPIView
或仅
APIView
使用 get 和 post 函数)

我遇到问题的地方是使用 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"
也能很好地使用卷曲。

python django-rest-framework put pytest-django
5个回答
23
投票

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 编码。


3
投票

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

这就是为什么有时这很棘手。即使使用 post 请求,如果您计划支持 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')

0
投票

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


0
投票

聚会迟到了。但对于 Google 员工,您应该在

django 测试客户端
中使用 format='json'

手动

json.dump
设置和设置
content_type
并不总是按预期工作。

resp = client.patch(self.url, data={'name': '123'}, format='json')

0
投票

尝试对 django TestCase 类进行 put / patch:

self.client.put(f'some_api/{id}/', params, format='multipart', content_type='multipart/form-data')

默认 content_type 为

application/octet-stream

使用 django 4.1 进行测试

© www.soinside.com 2019 - 2024. All rights reserved.