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

如何在DRF GenericViewSet、Mixin类视图中正确使用路径参数?

问题根源

你的代码无法生效是两个写法错误导致的:

  • DRF的@action装饰器的url_path参数不支持Django path() 函数的<类型:参数名>转换器语法,传入的字符串会被直接拼接为正则路由片段,你写的<str:period>会被当作普通字符匹配,不会被识别为路径参数。
  • url_name参数是用于路由反向解析的别名,不能包含尖括号、转换器标记或空格,你传入的<str: period>属于无效值,会直接导致路由注册失败。
修复方案

你可以任选以下两种方式实现,都能满足localhost:8000/api/ranks/{period}的访问需求。

方案1:保留@action装饰器,用正则捕获参数

修改views.py中的@action配置,用正则命名分组捕获period参数即可:

from rest_framework import mixins, status
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from rest_framework.decorators import action
# 提前导入你的Record、RecordSerializer模型和序列化器

class RankingView(mixins.ListModelMixin,
                  GenericViewSet):

    queryset = Record.objects.all()
    serializer_class = RecordSerializer

    # 修正url_path和url_name参数
    @action(
        methods=['GET'],
        detail=False,
        # 用正则命名分组捕获period参数,[^/.]+表示匹配除了/和.之外的任意字符
        url_path='(?P<period>[^/.]+)',
        url_name='rank-list'
    )
    def get_rank(self, request, period):
        # 编写你的业务逻辑,示例:根据period过滤数据
        filtered_records = self.get_queryset().filter(period=period)
        serializer = self.get_serializer(filtered_records, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

urls.py不需要修改,保持原有写法即可。如果需要限制period的可选值(比如只允许daily/weekly/monthly),可以把正则改成(?P<period>daily|weekly|monthly),不符合规则的参数会直接返回404。

方案2:手动注册路由,使用熟悉的path转换器语法

如果觉得正则写法不好记,可以去掉@action装饰器,手动在urls.py中注册带参数的路由,更符合Django原生路由的写法习惯。
首先修改views.py,去掉@action装饰器,直接写视图方法:

from rest_framework import mixins, status
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
# 提前导入你的Record、RecordSerializer模型和序列化器

class RankingView(mixins.ListModelMixin,
                  GenericViewSet):

    queryset = Record.objects.all()
    serializer_class = RecordSerializer

    def get_rank(self, request, period):
        # 业务逻辑和方案1一致
        filtered_records = self.get_queryset().filter(period=period)
        serializer = self.get_serializer(filtered_records, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

然后修改urls.py,手动追加带参数的路由映射:

from django.urls import path, include
from rest_framework.routers import DefaultRouter
# 导入你的RankingView
from .views import RankingView

router = DefaultRouter()
router.register(r'api/ranks', RankingView)

urlpatterns = [
    path('', include(router.urls)),
    # 手动绑定带period参数的路由到get_rank方法
    path(
        'api/ranks/<str:period>',
        RankingView.as_view({'get': 'get_rank'}),
        name='rank-list'
    )
]
验证方式

代码修改完成后,启动服务访问localhost:8000/api/ranks/weekly(把weekly替换为你需要传入的period值),即可正常进入对应视图方法拿到返回结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 22:09:14