Django TestCase调用self.client.post却发送GET请求触发405错误
Django测试中client.post实际发送GET请求导致405错误的解决方法
问题场景
编写Django集成测试时,self.client.get能正常发起请求,但调用self.client.post时,视图函数接收到的却是GET请求,最终返回HttpResponse("Method Not Allowed", 405),导致测试断言失败。
核心原因
Django测试客户端的post方法若传入完整绝对URL(如http://127.0.0.1:8201/v1/products/create),会触发内部重定向逻辑,自动将请求方法转为GET。测试客户端的设计初衷是优先使用相对路径模拟请求,绝对URL会被识别为外部跳转,从而改变请求方法。
解决步骤及代码修正
1. 将请求URL改为相对路径
去掉域名和端口,直接使用路由的相对路径,确保请求方法保持POST。
2. 正确传递请求数据(若为JSON格式)
如果视图期望接收JSON数据,需将字典序列化,并指定content_type,否则Django会默认按表单数据处理,可能导致解析失败。
3. 修正断言逻辑
response是HttpResponse对象,不能直接与字符串比较,需提取响应内容后再断言,同时建议先验证状态码。
修改后的测试代码
from django.test import TestCase import json class Test_Integration(TestCase): def test_create_exist_product(self): # 序列化JSON数据 request_data = json.dumps({"name": "product7", "latest_version": "0"}) # 使用相对路径发起POST请求 response = self.client.post( '/v1/products/create', data=request_data, content_type='application/json', follow=True, secure=False ) # 打印响应内容便于调试 print(response.content.decode()) # 先验证状态码,再断言响应文本 self.assertEqual(response.status_code, 200) self.assertEqual(response.content.decode(), "Product name already exists")
对应视图函数的补充(若处理JSON数据)
import json from django.http import HttpResponse import logging logger = logging.getLogger(__name__) def create_product(request): logger.info("Entering function create_product..") logger.info("REQUEST TYPE: "+str(request.method)) if request.method == "POST": # 解析JSON格式的请求体 try: data = json.loads(request.body) except json.JSONDecodeError: return HttpResponse("Invalid JSON data", status=400) name = data.get("name") latest_version = data.get("latest_version") # 业务逻辑:检查产品名称是否已存在 if name == "product7": # 示例判断逻辑,替换为实际业务代码 return HttpResponse("Product name already exists") # 其他创建产品的逻辑... return HttpResponse("Product created successfully") # 非POST请求返回405 return HttpResponse("Method Not Allowed", status=405)
验证效果
修改后重新运行测试,视图函数会正确接收到POST请求,执行对应的业务逻辑,返回预期的响应内容,测试断言即可通过。
内容的提问来源于stack exchange,提问作者S1n1struu
相关产品推荐
相关产品推荐

