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

如何在Django REST Framework的Post序列化器中展示分类与子分类

解决方案:嵌套分类-子分类-文章的序列化与分页实现

需求背景

需要在Post视图中实现分页(避免在分类视图分页导致文章数量不一致),同时返回嵌套结构的JSON,包含分类、子分类及对应文章,期望结构如下:

[
{
  "id": 1,
  "title": "Taomlar",
  "subcat": [
      {
        "id": 2,
        "title": "Milliy",
        "post": [
            {
              "id": 1,
              "title": "Palov",
              "summa": 300000
            },
            {
              "id": 2,
              "title": "Palov",
              "summa": 300000
            }
          ]
      }
    ]  
}     
]

现有代码

models.py

class Category(Base):
    title = models.CharField(max_length=200)
    parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')

    def __str__(self):
        return self.title

class Post(Base):
    title = models.CharField(max_length=225)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='post')

serializers.py

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = '__all__'

class PostSerializer(serializers.ModelSerializer):
    
    class Meta:
        model = Post
        fields = '__all__'

解决方案

1. 编写嵌套序列化器

从最内层的Post开始,逐层构建嵌套结构,修改serializers.py如下:

from rest_framework import serializers
from .models import Category, Post

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ['id', 'title', 'summa']  # 按需添加其他需要返回的字段

class SubCategorySerializer(serializers.ModelSerializer):
    post = PostSerializer(many=True, read_only=True)  # 关联子分类下的文章列表

    class Meta:
        model = Category
        fields = ['id', 'title', 'post']

class RootCategorySerializer(serializers.ModelSerializer):
    # 将模型中的children关联名映射为subcat字段,返回子分类列表
    subcat = SubCategorySerializer(source='children', many=True, read_only=True)

    class Meta:
        model = Category
        fields = ['id', 'title', 'subcat']

2. 实现视图分页

根据需求选择合适的分页逻辑:

方式一:对根分类分页(适合分类数量较多的场景)

from rest_framework.pagination import PageNumberPagination
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Category
from .serializers import RootCategorySerializer

class CategoryPostPagination(PageNumberPagination):
    page_size = 10  # 每页显示的根分类数量
    page_size_query_param = 'page_size'
    max_page_size = 100

class RootCategoryPostView(APIView):
    def get(self, request):
        # 查询所有根分类,预加载子分类和文章避免N+1查询
        root_categories = Category.objects.filter(parent=None).prefetch_related(
            'children__post'
        )
        paginator = CategoryPostPagination()
        paginated_categories = paginator.paginate_queryset(root_categories, request)
        serializer = RootCategorySerializer(paginated_categories, many=True)
        return paginator.get_paginated_response(serializer.data)

方式二:对文章分页(适合文章数量多,需要按文章数量分页的场景)

如果需要按文章数量分页,同时保持分类嵌套结构,可自定义逻辑:

from rest_framework.pagination import PageNumberPagination
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Category, Post
from .serializers import RootCategorySerializer

class PostPagination(PageNumberPagination):
    page_size = 2  # 每页显示的文章数量
    page_size_query_param = 'page_size'
    max_page_size = 100

class CategoryPostView(APIView):
    def get(self, request):
        paginator = PostPagination()
        # 获取分页后的文章集合
        paginated_posts = paginator.paginate_queryset(Post.objects.all(), request)
        # 提取这些文章所属的子分类ID和根分类ID
        sub_cat_ids = [post.category.id for post in paginated_posts]
        root_cat_ids = [cat.parent.id for cat in Category.objects.filter(id__in=sub_cat_ids) if cat.parent]
        # 查询根分类并预加载关联数据
        root_categories = Category.objects.filter(id__in=root_cat_ids).prefetch_related(
            'children__post'
        )
        serializer = RootCategorySerializer(root_categories, many=True)
        return paginator.get_paginated_response(serializer.data)

3. 关键注意点

  • 使用prefetch_related预加载关联数据,避免数据库N+1查询,提升接口性能
  • 通过source参数实现模型关联名到序列化器字段名的映射
  • 根据业务场景选择分页方式:根分类分页或文章分页

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 18:40:34