Django Admin:将Report模型字段总和展示至Profile视图的报错问题
解决Django Admin中Profile显示Report字段总和的报错问题
首先,你遇到的admin.E108报错原因很明确:你在ProfileAdmin的list_display里引用了user_report这个不存在的属性/方法。Django Admin的list_display只支持三类内容:模型本身的字段、ModelAdmin类中定义的方法、模型类中定义的可调用方法,不能直接写一个无意义的名称。
接下来根据你的模型关系(假设Report通过外键关联到Profile,比如Report里有profile = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='reports')),给你两种解决方案:
方案1:基础版(直接在Admin方法中计算)
直接在ProfileAdmin里定义一个方法,用来计算关联Report的Toxicity和Sportsmanship总和:
from django.contrib import admin from django.db.models import Sum from .models import Profile class ProfileAdmin(admin.ModelAdmin): # 把自定义方法加入list_display,替换原来的user_report list_display = ['id', 'user', 'get_total_report_score'] def get_total_report_score(self, obj): # 计算所有关联Report的两个字段总和,没有数据时返回0 total = obj.reports.aggregate( total_sum=Sum('Toxicity') + Sum('Sportsmanship') )['total_sum'] or 0 return f'total:{total}' # 设置这个方法在Admin列表中的表头名称 get_total_report_score.short_description = 'Total Report Score' admin.site.register(Profile, ProfileAdmin)
方案2:优化版(提前聚合,避免N+1查询)
如果你的Profile数据量较大,上面的方法会导致每个Profile对象都单独查询一次数据库(N+1查询问题),推荐用annotate提前在查询集里计算好总和:
from django.contrib import admin from django.db.models import Sum, F from .models import Profile class ProfileAdmin(admin.ModelAdmin): list_display = ['id', 'user', 'total_report_score'] def get_queryset(self, request): # 重写get_queryset,提前给每个Profile对象添加total_report_score字段 queryset = super().get_queryset(request) queryset = queryset.annotate( total_report_score=Sum('reports__Toxicity') + Sum('reports__Sportsmanship') ) return queryset def total_report_score(self, obj): # 直接使用提前聚合好的值,没有数据时返回0 return f'total:{obj.total_report_score or 0}' total_report_score.short_description = 'Total Report Score' admin.site.register(Profile, ProfileAdmin)
注意事项
- 如果你的
Profile和Report是一对一关系(OneToOneField),那计算逻辑可以简化为:def get_total_report_score(self, obj): if hasattr(obj, 'report'): total = obj.report.Toxicity + obj.report.Sportsmanship return f'total:{total}' return 'total:0' - 确保
Report模型中的外键字段related_name正确(比如上面的reports),如果没设置related_name,默认是report_set,那代码里要改成obj.report_set.aggregate(...)。
内容的提问来源于stack exchange,提问作者Shadowwz
相关产品推荐
相关产品推荐

