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

能否在DRF中通过不同URL模式过滤ListView?用ViewSets实现分类、子分类路由

当然没问题!完全可以只靠Django REST Framework的ViewSets和Routers实现你要的分类、子分类商品列表路由,我给你详细说说具体怎么操作:

核心思路

DRF的默认Router只会生成标准的CRUD路由(比如/items/、/items/<pk>/),但我们可以通过给ViewSet添加自定义Action,再让Router自动识别并生成你需要的/items/category/、/items/category/subcategory/这类嵌套路由。

具体实现代码

1. 改造你的ItemViewSet

在原本的ItemViewSet里添加两个自定义Action方法,分别处理分类和子分类的商品列表查询:

from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Item
from .serializers import ItemSerializer

class ItemViewSet(viewsets.ModelViewSet):
    queryset = Item.objects.all()
    serializer_class = ItemSerializer

    # 展示指定分类下的商品列表
    @action(detail=False, methods=['get'], url_path='category/(?P<category_slug>[^/.]+)')
    def list_by_category(self, request, category_slug=None):
        # 这里假设你的Category模型用slug作为标识,要是用id就改成category__id=category_slug
        filtered_items = self.queryset.filter(category__slug=category_slug)
        serializer = self.get_serializer(filtered_items, many=True)
        return Response(serializer.data)

    # 展示指定子分类下的商品列表
    @action(detail=False, methods=['get'], url_path='category/(?P<category_slug>[^/.]+)/subcategory/(?P<subcategory_slug>[^/.]+)')
    def list_by_subcategory(self, request, category_slug=None, subcategory_slug=None):
        # 同样,子分类如果用id就替换成subcategory__id=subcategory_slug
        filtered_items = self.queryset.filter(
            category__slug=category_slug,
            subcategory__slug=subcategory_slug
        )
        serializer = self.get_serializer(filtered_items, many=True)
        return Response(serializer.data)

2. 保持Router配置不变

你的Router注册代码不需要修改,还是像之前一样注册ItemViewSet:

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ItemViewSet

router = DefaultRouter()
router.register(r'items', ItemViewSet)

urlpatterns = [
    path('', include(router.urls)),
]
关键细节说明
  • @action装饰器的detail=False:表示这是列表级别的Action,不会生成带<pk>的路由,符合你要的列表展示需求。
  • url_path参数:用正则表达式捕获分类/子分类的标识(这里用slug,你可以换成id,只需要修改正则和过滤条件),Router会自动把这个路径拼接到/items/后面,生成你要的路由:
    • /items/category/<你的分类slug>/
    • /items/category/<你的分类slug>/subcategory/<你的子分类slug>/
  • 扩展性:如果需要给这些接口加权限、分页、过滤,直接在ViewSet里配置(比如加permission_classes、pagination_class),和普通的ViewSet配置完全一致。
额外提示

如果你的分类/子分类用的是数据库ID而不是slug,只需要做两处修改:

  1. 把url_path里的正则改成(?P<category_id>\d+)和(?P<subcategory_id>\d+)
  2. 把过滤条件里的category__slug改成category__id,subcategory__slug改成subcategory__id

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:47:51