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

如何在Django中使用通用类视图实现嵌套路由(非ViewSets)

用DRF通用类视图实现嵌套路由的问题解决

需求说明

需要实现以下API端点:

  • /products/
  • /products/<product_pk>/
  • /products/<product_pk>/reviews/
  • /products/<product_pk>/reviews/<review_pk>/

原代码问题分析

原URL配置

# urls.py
from django.urls import path, include
from . import views

urlpatterns = [
    path("products/", views.ProductList.as_view()),
    path(
        "products/<int:product_pk>/",
        include(
            [
                path("", views.ProductDetail.as_view()),
                path("reviews/", views.ReviewList.as_view()),
                path("reviews/<int:review_pk>/", views.ReviewDetail.as_view()),
            ]
        ),
    )
]

原视图代码

# views.py
class ProductList(ListCreateAPIView):
    queryset = Product.objects.all()
    serializer = ProductSerializer


class ProductDetail(RetrieveUpdateDestroyAPIView):
    queryset = Product.objects.all()
    serializer = ProductSerializer
    lookup_field = "product_pk"


class ReviewList(ListCreateAPIView):
    serializer_class = ReviewSerializer

    def get_queryset(self):
        return Review.objects.filter(product_id=self.kwargs["product_pk"]).all()

    def get_serializer_context(self):
        return {"product_id": self.kwargs["product_pk"]}


class ReviewDetail(RetrieveUpdateDestroyAPIView):
    serializer_class = ReviewSerializer
    lookup_field = "review_pk"

    def get_queryset(self):
        return Review.objects.filter(product_id=self.kwargs["product_pk"]).all()

问题1解决:/products/1/reviews/1 报错

报错原因:ReviewDetail里的lookup_field被设置为review_pk,但Review模型中不存在这个字段。lookup_field的作用是指定模型中用于查询的字段名,URL里的参数名需要用lookup_url_kwarg来对应。

修改ReviewDetail视图:

class ReviewDetail(RetrieveUpdateDestroyAPIView):
    serializer_class = ReviewSerializer
    lookup_field = "id"  # 对应Review模型的主键字段
    lookup_url_kwarg = "review_pk"  # 对应URL中的参数名

    def get_queryset(self):
        return Review.objects.filter(product_id=self.kwargs["product_pk"]).all()

这样DRF会用URL中的review_pk值,匹配Review模型的id字段,解决字段找不到的错误。

问题2解决:/products/1 报错

报错原因:ProductDetail里的lookup_field设为product_pk,但Product模型中没有这个字段,同样混淆了lookup_field和lookup_url_kwarg的作用。

修改ProductDetail视图:

class ProductDetail(RetrieveUpdateDestroyAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    lookup_field = "id"  # 对应Product模型的主键字段
    lookup_url_kwarg = "product_pk"  # 对应URL中的参数名

这里lookup_field指定用模型的id字段查询,lookup_url_kwarg告诉DRF从URL的product_pk参数中获取查询值,既满足URL参数命名需求,又不会和评论的查询字段冲突。

最终完整视图代码

# views.py
from rest_framework.generics import (
    ListCreateAPIView,
    RetrieveUpdateDestroyAPIView
)
from .models import Product, Review
from .serializers import ProductSerializer, ReviewSerializer


class ProductList(ListCreateAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer  # 原代码写的serializer是错误的,需改为serializer_class


class ProductDetail(RetrieveUpdateDestroyAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    lookup_field = "id"
    lookup_url_kwarg = "product_pk"


class ReviewList(ListCreateAPIView):
    serializer_class = ReviewSerializer

    def get_queryset(self):
        return Review.objects.filter(product_id=self.kwargs["product_pk"])

    def get_serializer_context(self):
        return {"product_id": self.kwargs["product_pk"]}


class ReviewDetail(RetrieveUpdateDestroyAPIView):
    serializer_class = ReviewSerializer
    lookup_field = "id"
    lookup_url_kwarg = "review_pk"

    def get_queryset(self):
        return Review.objects.filter(product_id=self.kwargs["product_pk"])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:55:56