feat: base 修改customlist以支持children展示

This commit is contained in:
caoqianming 2025-12-26 15:53:17 +08:00
parent a8ae8ee32a
commit 2288e4e085
2 changed files with 43 additions and 15 deletions

View File

@ -19,6 +19,8 @@ from rest_framework.decorators import action
from apps.utils.serializers import ComplexSerializer from apps.utils.serializers import ComplexSerializer
from django.db.models import F from django.db.models import F
from django.db import transaction from django.db import transaction
from collections import defaultdict
from django.db import models
# 实例化myLogger # 实例化myLogger
myLogger = logging.getLogger('log') myLogger = logging.getLogger('log')
@ -214,17 +216,44 @@ class CustomListModelMixin(ListModelMixin):
type=openapi.TYPE_STRING, required=False), type=openapi.TYPE_STRING, required=False),
]) ])
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset()) queryset = self.filter_queryset(self.get_queryset())
model = queryset.model
page = self.paginate_queryset(queryset) page = self.paginate_queryset(queryset)
if page is not None: if page is not None:
serializer = self.get_serializer(page, many=True) objs = page
data = self.add_info_for_list(serializer.data) else:
return self.get_paginated_response(data) objs = queryset
# ===== 默认空映射(不支持 parent 的 model 也能正常返回) =====
serializer = self.get_serializer(queryset, many=True) children_map = {}
count_map = {}
# ===== 只在 model 有 parent FK 时才构建 =====
if self.request.query_params.get('with_children', 'no') in ['yes', 'count']:
has_parent = any(
f.name == 'parent' and isinstance(f, models.ForeignKey)
for f in model._meta.get_fields()
)
if has_parent:
parent_ids = [obj.id for obj in objs]
children_map = defaultdict(list)
count_map = defaultdict(int)
if parent_ids:
children_qs = self.get_queryset().filter(parent_id__in=parent_ids)
for child in children_qs:
children_map[child.parent_id].append(child)
count_map[child.parent_id] += 1
# ===== 序列化 =====
serializer = self.get_serializer(
objs,
many=True,
context={
'request': request,
'children_map': children_map,
'count_map': count_map,
}
)
data = self.add_info_for_list(serializer.data) data = self.add_info_for_list(serializer.data)
if page is not None:
return self.get_paginated_response(data)
return Response(data) return Response(data)
def add_info_for_list(self, data): def add_info_for_list(self, data):

View File

@ -25,21 +25,20 @@ class TreeSerializerMixin:
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
request = self.context.get('request', None) request = self.context.get('request', None)
self.with_children = request.query_params.get('with_children', 'no') if request else 'no' self.with_children = request.query_params.get('with_children', 'no') if request else 'no'
if self.with_children in ['yes', 'count']: if self.with_children in ('yes', 'count'):
if 'children' not in self.fields: self.fields.setdefault('children_count', serializers.SerializerMethodField())
self.fields['children'] = serializers.SerializerMethodField() if self.with_children == 'yes':
if 'children_count' not in self.fields: self.fields.setdefault('children', serializers.SerializerMethodField())
self.fields['children_count'] = serializers.SerializerMethodField()
def get_children(self, obj): def get_children(self, obj):
if hasattr(obj, 'parent') and self.with_children == 'yes': if hasattr(obj, 'parent') and self.with_children == 'yes':
serializer_class = self.__class__ children = self.context.get('children_map', {}).get(obj.id, [])
return serializer_class(obj.__class__.objects.filter(parent=obj), many=True, context=self.context).data return self.__class__(children, many=True, context=self.context).data
return [] return []
def get_children_count(self, obj): def get_children_count(self, obj):
if hasattr(obj, 'parent') and self.with_children in ['yes', 'count']: if hasattr(obj, 'parent') and self.with_children in ['yes', 'count']:
return obj.__class__.objects.filter(parent=obj).count() return self.context.get('count_map', {}).get(obj.id, 0)
return 0 return 0
class CustomModelSerializer(DynamicFieldsMixin, TreeSerializerMixin, serializers.ModelSerializer): class CustomModelSerializer(DynamicFieldsMixin, TreeSerializerMixin, serializers.ModelSerializer):