Django关联School与Student模型统计学校学生数无结果如何解决
Django关联模型统计学生人数修复方案
核心问题原因
- 统计语句
school.objects.annotate(num_of_students=Count('student'))位置错误:写在序列化器类定义体中只会在模块加载时执行一次,不会作用到每次查询的实例上 - 统计结果字段
num_of_students没有加入序列化器的返回字段列表,序列化时自动忽略 - 外键命名不规范,默认反向关联名不匹配会导致Count统计失效:Student模型中对外键命名为
school_id,Django默认生成的反向关联名为student_set,直接写Count('student')找不到关联数据 - 查询集没有做关联预加载和统计注解,即使序列化器加了字段也拿不到统计值
修复步骤
1. 调整模型(可选但推荐)
规范外键命名,添加反向关联名,同时补全CharField必填的max_length参数:
class School(models.Model): name = models.CharField(max_length=100) city = models.CharField(max_length=50) street = models.CharField(max_length=100) class Student(models.Model): # 外键命名为school,添加related_name方便反向查询 school = models.ForeignKey(School, on_delete=models.CASCADE, related_name='students') first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50)
如果不想修改原有外键名school_id,仅需给外键加related_name即可:
school_id = models.ForeignKey(School, on_delete=models.CASCADE, related_name='students')
2. 调整序列化器
在SchoolSerializer中添加统计字段,加入返回字段列表:
from rest_framework import serializers from django.db.models import Count from .models import School, Student class SchoolSerializer(serializers.HyperlinkedModelSerializer): # 新增只读的学生统计字段 num_of_students = serializers.IntegerField(read_only=True) class Meta: model = School fields = ['name', 'num_of_students'] class StudentSerializer(serializers.HyperlinkedModelSerializer): # 如果外键名是school_id,此处需要加source参数:source='school_id' school = SchoolSerializer(read_only=True) class Meta: model = Student fields = ['first_name', 'last_name', 'school']
3. 调整视图查询集
在查询时提前做关联加载和统计注解,避免N+1查询问题:
from rest_framework import viewsets from .models import Student from .serializers import StudentSerializer class StudentViewSet(viewsets.ModelViewSet): serializer_class = StudentSerializer # 预加载关联学校数据,同时注解统计每个学校的学生数 queryset = Student.objects.select_related('school').annotate( num_of_students=Count('school__students') )
扩展:直接返回学校维度的统计数据
如果需要直接获取所有学校的学生统计列表,新增School的视图即可:
class SchoolViewSet(viewsets.ModelViewSet): serializer_class = SchoolSerializer # 直接注解统计每个学校的学生数 queryset = School.objects.annotate(num_of_students=Count('students'))
内容的提问来源于stack exchange,提问作者user13066942
相关产品推荐
相关产品推荐

