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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 16:20:44