You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中已匹配URL仍返回404错误,求排查方案

Django接口404问题排查与解决

核心问题分析

你遇到的404错误有两个关键原因:

  1. 路由匹配规则:Django REST Framework的DefaultRouter注册ViewSet时,默认生成两类路由:
    • 列表路由:api/update-last-high/(带尾斜杠,对应list操作)
    • 详情路由:api/update-last-high/<pk>/(需要主键参数,对应update/partial_update操作)
      你访问的api/update-last-high既没有尾斜杠,也没有主键参数,不符合任何已生成的路由规则。
  2. ViewSet继承与方法规范:
    • 你的UpdateLast仅继承了GenericViewSet和UpdateModelMixin,后者只提供详情页的更新操作(需要主键),不会生成列表路由。
    • 自定义的get方法不符合ViewSet规范,ViewSet中列表查询对应的方法是list,而非get,且直接返回QuerySet会报错,必须返回Response对象。

针对性解决方案

方案1:实现列表查询接口(无需主键)

如果你的get方法是想返回所有XYZModel数据,按以下步骤修改:

  1. 补充继承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)
    
  2. 访问时使用带尾斜杠的路径:api/update-last-high/

方案2:实现详情更新接口(需要主键)

如果你的接口仅用于更新单个XYZModel实例,按以下步骤调整:

  1. 确保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)
    
  2. 访问时必须带上主键参数,比如:api/update-last-high/1/(1为目标实例的ID),且请求方法需用PATCH(对应partial_update)

可选:关闭尾斜杠要求

若不想使用尾斜杠,可在项目settings.py中添加:

APPEND_SLASH = False

但不推荐此做法,会破坏DRF路由的默认规范。

内容的提问来源于stack exchange,提问作者Sid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 20:15:33