Django中已匹配URL仍返回404错误,求排查方案
Django接口404问题排查与解决
核心问题分析
你遇到的404错误有两个关键原因:
- 路由匹配规则:Django REST Framework的
DefaultRouter注册ViewSet时,默认生成两类路由:- 列表路由:
api/update-last-high/(带尾斜杠,对应list操作) - 详情路由:
api/update-last-high/<pk>/(需要主键参数,对应update/partial_update操作)
你访问的api/update-last-high既没有尾斜杠,也没有主键参数,不符合任何已生成的路由规则。
- 列表路由:
- ViewSet继承与方法规范:
- 你的
UpdateLast仅继承了GenericViewSet和UpdateModelMixin,后者只提供详情页的更新操作(需要主键),不会生成列表路由。 - 自定义的
get方法不符合ViewSet规范,ViewSet中列表查询对应的方法是list,而非get,且直接返回QuerySet会报错,必须返回Response对象。
- 你的
针对性解决方案
方案1:实现列表查询接口(无需主键)
如果你的get方法是想返回所有XYZModel数据,按以下步骤修改:
- 补充继承
ListModelMixin,让DefaultRouter生成列表路由:from rest_framework.mixins import ListModelMixin, UpdateModelMixin from rest_framework.response import Response from rest_framework import status from django.db.models import Case, When, Value, F class UpdateLast(viewsets.GenericViewSet, ListModelMixin, UpdateModelMixin): queryset = XYZModel.objects.all() # 必须指定queryset或实现get_queryset方法 def list(self, request): # 替换原get方法,返回Response对象 data = XYZModel.objects.values() return Response(data) # 保留你的partial_update方法,同时修复内部逻辑问题 def partial_update(self, request, *args, **kwargs): if not request.user.is_superuser: return Response(status=status.HTTP_403_FORBIDDEN) with transaction.atomic(): tic = request.data.get('tic') high = request.data.get('high') # 避免循环字典的错误,直接获取所需参数 if tic and high: XYZModel.objects.filter(ticker=tic, trail=True).update( last_high=Case( When(last_high__lt=high, then=Value(high)), default=F('last_high') ) ) return Response(status=status.HTTP_200_OK) - 访问时使用带尾斜杠的路径:
api/update-last-high/
方案2:实现详情更新接口(需要主键)
如果你的接口仅用于更新单个XYZModel实例,按以下步骤调整:
- 确保
UpdateLast指定queryset(GenericViewSet必须):from rest_framework.response import Response from rest_framework import status from django.db.models import Case, When, Value, F class UpdateLast(viewsets.GenericViewSet, UpdateModelMixin): queryset = XYZModel.objects.all() def partial_update(self, request, *args, **kwargs): # 修复request.data循环的错误,以及权限判断前置 if not request.user.is_superuser: return Response(status=status.HTTP_403_FORBIDDEN) with transaction.atomic(): tic = request.data.get('tic') high = request.data.get('high') if tic and high: XYZModel.objects.filter(ticker=tic, trail=True).update( last_high=Case( When(last_high__lt=high, then=Value(high)), default=F('last_high') ) ) return Response(status=status.HTTP_200_OK) - 访问时必须带上主键参数,比如:
api/update-last-high/1/(1为目标实例的ID),且请求方法需用PATCH(对应partial_update)
可选:关闭尾斜杠要求
若不想使用尾斜杠,可在项目settings.py中添加:
APPEND_SLASH = False
但不推荐此做法,会破坏DRF路由的默认规范。
内容的提问来源于stack exchange,提问作者Sid
相关产品推荐
相关产品推荐

