如何在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
相关产品推荐
相关产品推荐

