如何在Django REST中查询同表一对多关联的子分类?
解决方案
首先确认你的Category模型是否正确配置了自关联的反向关系,确保related_name设置正确,这样才能方便地通过主分类获取子分类:
from django.db import models class Category(models.Model): name = models.CharField(max_length=100, unique=True) # parent字段关联自身,related_name用来反向查询子分类 parent = models.ForeignKey( 'self', on_delete=models.CASCADE, related_name='children', null=True, blank=True ) def __str__(self): return self.name
1. 编写序列化器
创建序列化器来序列化子分类数据:
from rest_framework import serializers from .models import Category class CategorySerializer(serializers.ModelSerializer): class Meta: model = Category fields = ['id', 'name', 'parent']
2. 编写视图处理查询逻辑
使用ListAPIView自定义查询集,支持通过主分类ID或名称获取子分类:
from rest_framework.generics import ListAPIView from rest_framework.exceptions import NotFound from .models import Category from .serializers import CategorySerializer class CategoryChildrenListView(ListAPIView): serializer_class = CategorySerializer def get_queryset(self): parent_id = self.request.query_params.get('parent_id') parent_name = self.request.query_params.get('parent_name') if parent_id: # 通过主分类ID筛选子分类 return Category.objects.filter(parent_id=parent_id) elif parent_name: # 通过主分类名称找到对应主分类,再获取其子分类 try: parent_category = Category.objects.get(name=parent_name) return parent_category.children.all() except Category.DoesNotExist: raise NotFound(detail="指定的主分类不存在") # 无查询参数时返回空列表或按需求调整 return Category.objects.none()
3. 配置URL路由
将视图映射到URL,允许通过查询参数传递主分类ID或名称:
from django.urls import path from .views import CategoryChildrenListView urlpatterns = [ path('categories/children/', CategoryChildrenListView.as_view(), name='category-children'), ]
使用示例
- 通过主分类ID查询:
GET /categories/children/?parent_id=11 - 通过主分类名称查询:
GET /categories/children/?parent_name=zoogdieren
两种请求都会返回该主分类下的所有子分类数据。如果需要整合到现有ViewSet中,也可以重写list方法实现相同逻辑,示例如下:
from rest_framework.viewsets import ModelViewSet from rest_framework.response import Response from rest_framework.exceptions import NotFound from .models import Category from .serializers import CategorySerializer class CategoryViewSet(ModelViewSet): queryset = Category.objects.all() serializer_class = CategorySerializer def list(self, request, *args, **kwargs): parent_id = request.query_params.get('parent_id') parent_name = request.query_params.get('parent_name') if parent_id or parent_name: if parent_id: queryset = Category.objects.filter(parent_id=parent_id) else: try: parent = Category.objects.get(name=parent_name) queryset = parent.children.all() except Category.DoesNotExist: raise NotFound(detail="指定的主分类不存在") serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) # 无查询参数时执行默认list逻辑 return super().list(request, *args, **kwargs)
内容的提问来源于stack exchange,提问作者mightycode Newton
相关产品推荐
相关产品推荐

