Django测试中创建的Task查询失败,实际服务器正常问题求助
Django测试中Task查询失败问题排查
错误详情
错误:test_task_check_success (tasks.tests.TaskCheckTestCase.test_task_check_success) 回溯(最近的调用最后): 文件 "C:\Users\gns03\OneDrive\바탕 화면\사전과제\tasks\tests.py",第119行,在test_task_check_success中 response = self.client.get(self.url, params=self.data1, **header, format='json') ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\rest_framework\test.py",第289行,在get中 response = super().get(path, data=data, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\rest_framework\test.py",第206行,在get中 return self.generic('GET', path, **r) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\rest_framework\test.py",第234行,在generic中 return super().generic( ^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\test\client.py",第609行,在generic中 return self.request(**r) ^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\rest_framework\test.py",第286行,在request中 return super().request(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\rest_framework\test.py",第238行,在request中 request = super().request(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\test\client.py",第891行,在request中 self.check_exception(response) 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\test\client.py",第738行,在check_exception中 raise exc_value 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\core\handlers\exception.py",第55行,在inner中 response = get_response(request) ^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\core\handlers\base.py",第197行,在_get_response中 response = wrapped_callback(request, *callback_args, **callback_kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\views\decorators\csrf.py",第56行,在wrapper_view中 return view_func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\views\generic\base.py",第104行,在view中 return self.dispatch(request, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\rest_framework\views.py",第509行,在dispatch中 response = self.handle_exception(exc) ^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\rest_framework\views.py",第469行,在handle_exception中 self.raise_uncaught_exception(exc) 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\rest_framework\views.py",第480行,在raise_uncaught_exception中 raise exc 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\rest_framework\views.py",第506行,在dispatch中 response = handler(request, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\OneDrive\바탕 화면\사전과제\tasks\views.py",第69行,在get中 task_instance = Task.objects.get(id=request.data.get('task')) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\db\models\manager.py",第87行,在manager_method中 return getattr(self.get_queryset(), name)(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "C:\Users\gns03\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\db\models\query.py",第637行,在get中 raise self.model.DoesNotExist( tasks.models.Task.DoesNotExist: 匹配查询的Task不存在。
相关代码
views.py
class TaskCheckView(APIView): def get(self, request): try: task_instance = Task.objects.get(id=request.data.get('task')) except Task.DoesNotExist: return Response({ 'error_code': status.HTTP_404_NOT_FOUND, 'error': '해당 업무를 찾을 수 없습니다.'}, status=status.HTTP_404_NOT_FOUND) subtasks_related_to_task = SubTask.objects.filter(task=task_instance) subtasks_data = SubTaskSerializer(subtasks_related_to_task, many=True).data serializer = TaskCheckSerializer(data={ 'task_id': task_instance.id, 'task_team': ','.join([str(team.id) for team in task_instance.team.all()]), 'title': task_instance.title, 'content': task_instance.content, 'is_complete': task_instance.is_complete, 'completed_data': task_instance.completed_data, 'created_at': task_instance.created_at, 'modified_at': task_instance.modified_at, 'subtasks': subtasks_data }) if serializer.is_valid(): return Response({'data': serializer.data, 'status': status.HTTP_200_OK}, status=status.HTTP_200_OK) return Response({'error_code': status.HTTP_400_BAD_REQUEST}, status=status.HTTP_400_BAD_REQUEST)
serializers.py
class TaskCheckSerializer(serializers.Serializer): task_id = serializers.IntegerField() task_team = serializers.CharField() title = serializers.CharField() content = serializers.CharField() is_complete = serializers.BooleanField() completed_data = serializers.DateTimeField(allow_null=True) created_at = serializers.DateField() modified_at = serializers.DateField() subtasks = SubTaskSerializer(many=True)
tests.py
class TaskCheckTestCase(APITestCase): def setUp(self): self.url = '/task/detail/' self.user = User.objects.create(email='test1@naver.com', name='팀원1') self.user.set_password("qwer1234") self.user.save() self.token, created = Token.objects.get_or_create(user=self.user) self.team1 = Team.objects.create(team='team1') self.task = Task.objects.create(title='테스트 제목', content='테스트', create_user=self.user) self.task.team.set([self.team1.id]) self.subtask = SubTask.objects.create(task=self.task, team=self.team1) self.data1={ 'task': str(self.task.id) } self.data2={ 'task': '999' } def test_task_check_success(self): header = {'HTTP_AUTHORIZATION': f'Token {self.token}'} response = self.client.get(self.url, data=self.data1, **header, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK)
问题描述
我在服务器中查询实际的Task ID没有问题,但运行测试代码时,查询在setUp中创建的self.task却出现错误。问题出在哪里?
我没有得到404错误,出现错误的原因是获取实例的try部分未捕获异常,直接抛出了错误信息。
问题原因与修复方案
1. GET请求参数获取方式错误
REST Framework中,request.data仅用于处理POST/PUT/PATCH等包含请求体的请求,GET请求的参数需要从request.query_params中获取。你当前在TaskCheckView.get方法中用request.data.get('task'),会导致始终获取不到GET请求传递的参数,最终查询id=None的Task,抛出DoesNotExist异常。
修复views.py:
def get(self, request): try: # 从查询参数获取task id,并转换为整数类型 task_id = request.query_params.get('task') if not task_id: return Response({ 'error_code': status.HTTP_400_BAD_REQUEST, 'error': 'task参数不能为空'}, status=status.HTTP_400_BAD_REQUEST) task_instance = Task.objects.get(id=int(task_id)) except Task.DoesNotExist: return Response({ 'error_code': status.HTTP_404_NOT_FOUND, 'error': '해당 업무를 찾을 수 없습니다.'}, status=status.HTTP_404_NOT_FOUND) except ValueError: return Response({ 'error_code': status.HTTP_400_BAD_REQUEST, 'error': 'task参数必须是有效的整数'}, status=status.HTTP_400_BAD_REQUEST) # 后续代码保持不变
2. 测试代码中参数传递优化
虽然Django测试客户端的get方法中data参数会自动转为查询参数,但更规范的写法是使用params参数明确传递查询参数,同时task直接用整数类型更严谨:
修复tests.py的test_task_check_success方法:
def test_task_check_success(self): header = {'HTTP_AUTHORIZATION': f'Token {self.token}'} # 使用params传递GET查询参数,task用整数类型 response = self.client.get(self.url, params={'task': self.task.id}, **header) self.assertEqual(response.status_code, status.HTTP_200_OK)
3. 异常捕获不完整问题
之前的代码只捕获了Task.DoesNotExist异常,但当task参数为空或不是整数时,会抛出ValueError,这个异常没有被捕获,导致直接抛出未处理的异常。上面的修复中已经添加了ValueError的捕获处理,确保所有可能的异常都被正确处理并返回对应的响应。
内容的提问来源于stack exchange,提问作者성낙훈
相关产品推荐
相关产品推荐

