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

如何用Django REST ModelViewSet按指定图书馆过滤图书?

解决方法:用ModelViewSet实现按图书馆过滤图书

你的核心问题在于ModelViewSet的queryset属性是在类初始化时就执行的,无法直接获取请求时的URL参数,而且DefaultRouter的注册方式不支持带捕获参数的路径。下面是分步解决的方案:

1. 重写BookViewSet的get_queryset方法

把原来硬编码的queryset替换成动态获取URL参数并过滤的逻辑:

class BookViewSet(viewsets.ModelViewSet):
    serializer_class = BookSerializer

    def get_queryset(self):
        # 从URL的kwargs中提取library_id参数
        library_id = self.kwargs.get('library_id')
        # 过滤出属于该图书馆的所有图书
        return Book.objects.filter(which_library=library_id)
    
    # 可选:如果需要创建图书时自动关联到当前图书馆,重写perform_create
    def perform_create(self, serializer):
        # 获取指定的图书馆实例
        library = Library.objects.get(pk=self.kwargs['library_id'])
        # 保存时自动设置which_library字段
        serializer.save(which_library=library)

为什么要这么做?因为queryset属性是在类加载时就执行的,此时还没有请求进来,根本拿不到library_id这个URL参数。而get_queryset方法是在每次请求时调用的,能动态获取当前请求的参数。

2. 修正URL配置

DefaultRouter的register方法不支持带捕获组(比如(?P<library_id>[0-9]+))的路径,所以需要手动为BookViewSet映射URL,同时让路径更符合RESTful风格(把图书馆ID放在前面,比如/libraries/1/books/):

from django.urls import path, include
from rest_framework import routers

router = routers.DefaultRouter()
router.register(r'libraries', LibraryViewSet)

urlpatterns = [
    # 保留原来的图书馆路由
    path('', include(router.urls)),
    # 图书列表和创建接口
    path('libraries/<int:library_id>/books/', BookViewSet.as_view({
        'get': 'list',
        'post': 'create'
    }), name='library-books'),
    # 单本图书的详情、更新、删除接口
    path('libraries/<int:library_id>/books/<int:pk>/', BookViewSet.as_view({
        'get': 'retrieve',
        'put': 'update',
        'patch': 'partial_update',
        'delete': 'destroy'
    }), name='library-book-detail'),
]

这样配置后:

  • GET /libraries/1/books/ 会返回ID为1的图书馆下的所有图书
  • POST /libraries/1/books/ 会创建一本属于该图书馆的图书(如果重写了perform_create,不需要在请求体里传which_library)
  • GET /libraries/1/books/2/ 会返回该图书馆下ID为2的图书(如果存在)

可选:使用嵌套路由包(更简洁)

如果你不想手动写URL,可以使用drf-nested-routers第三方包来实现嵌套路由:

  1. 安装包:pip install drf-nested-routers
  2. 修改URL配置:
from rest_framework_nested import routers

router = routers.DefaultRouter()
router.register(r'libraries', LibraryViewSet)

# 创建嵌套路由,基于library路由
library_router = routers.NestedDefaultRouter(router, r'libraries', lookup='library')
library_router.register(r'books', BookViewSet, basename='library-book')

urlpatterns = router.urls + library_router.urls

这种方式会自动生成和上面手动配置一样的URL,而且不需要手动映射HTTP方法,更符合DRF的风格。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:12:07