Django Admin计算字段返回Grade模型id平均分,如何指定mark字段?
问题
尝试在Django Admin的Student模型列表中添加计算列,展示关联Grade模型里mark字段的平均分,但执行Avg聚合时,返回的是Grade模型id字段的平均分,而非mark字段。
相关代码:
models.py
class Student(models.Model): first_name = models.CharField(max_length=255) last_name = models.CharField(max_length=255) email = models.EmailField(unique=True) def __str__(self) -> str: return self.last_name class Meta: ordering = ['last_name'] class Module(models.Model): module = models.CharField(max_length=255) class Grade(models.Model): mark = models.PositiveSmallIntegerField(null=True) module_id = models.ForeignKey(Module, on_delete=models.PROTECT) student_id = models.ForeignKey(Student, on_delete=models.PROTECT) def __str__(self) -> str: return str(self.mark)
admin.py
@admin.register(models.Student) class StudentAdmin(admin.ModelAdmin): list_display = ['id', 'first_name', 'last_name', 'average_grade'] def average_grade(self, student): return student.average_grade def get_queryset(self, request): return super().get_queryset(request).annotate( average_grade = Avg('grade') )
解决方法
问题出在annotate的参数上:直接写'grade'时,Django会默认使用关联模型(Grade)的主键字段(id)进行聚合。要指定聚合mark字段,需要用双下划线关联到Grade模型的目标字段,即'grade__mark'。
另外,由于Grade的mark字段允许为null,建议用Coalesce把null值替换为0,避免平均分计算结果为None,同时记得导入对应的函数。
修改后的admin.py代码:
from django.db.models import Avg, Coalesce # 其他导入保持不变 @admin.register(models.Student) class StudentAdmin(admin.ModelAdmin): list_display = ['id', 'first_name', 'last_name', 'average_grade'] def average_grade(self, student): # 可选:格式化输出,保留一位小数 return round(student.average_grade, 1) if student.average_grade else 0 def get_queryset(self, request): return super().get_queryset(request).annotate( average_grade = Avg(Coalesce('grade__mark', 0)) )
补充说明:原Grade模型的__str__方法直接返回整数类型的self.mark会报错,已修改为return str(self.mark)确保返回字符串类型。
内容的提问来源于stack exchange,提问作者Chris Laver
相关产品推荐
相关产品推荐

