首页 > 解决方案 > 来自特定学科的特定学生的加权平均值

问题描述

我已经学习 Python 几天了,并且尝试完成一个小型的 Django 学校模型。

我现在的目标是能够为学生分配特定科目(例如物理)的加权分数,然后将这些加权分数相加,并为学生返回他的科目的加权平均值。

例如,学生 A 的物理分数为 3(分数)* 2(体重),物理分数为 3*3,数学分数为 2*4、3*1。我的目标是返回:

学生 A
物理平均分:2.5

学生 A
数学平均分:2.2

现在我一直在尝试以这种方式实现它,但它不起作用。加权平均值根本不会显示。

class Score(models.Model):
    scale = models.PositiveIntegerField(choices=scales_list)
    student = models.ForeignKey(Student, on_delete=models.CASCADE)
    subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
    task = models.ForeignKey(Task, on_delete=models.CASCADE)
    weight = models.PositiveIntegerField(default=1)
    
    def _weighted_score(self):
        return self.scale * self.weight

    weighted_score = property(_weighted_score)

    def _weighted_average(self):
        qs = self.objects.all().annotate(
            score_sum = sum('scale'),
            weighted_sum = sum('weight'),
            weighted_avg = Sum((F('scale') * F('weight')), output_field=FloatField() ) / Sum('weighted_sum'), output_field=FloatField()
        )
        return weighted_avg
    
    weighted_average = property(_weighted_average)

谢谢。

标签: pythondjango

解决方案


这可能是问题:

def _weighted_average(self):
        qs = self.objects.all().annotate(
            score_sum = sum('scale'),
            weighted_sum = sum('weight'),
            weighted_avg = Sum((F('scale') * F('weight')), output_field=FloatField() ) / Sum('weighted_sum'), output_field=FloatField()
        )
        return weighted_avg

一方面,为了清晰和简洁,您可以使用@propertyDjango 的 cached_property。无论如何,您面临的问题是使用self. Self 指的是您正在使用的给定对象。它是一个单一的实例,例如 a .get()not a.filter()所以你不能再链接那些查询集的东西了。

您是否打算根据当前过滤器制作查询集?如果是这样,您应该@classmethod像这样:

class Blah(models.Model):
    id = BigAutoField()

    @classmethod
    def blah(cls, qs):
        return qs.filter("more filters")

    @property
    def get_id(self):
        return self.id

hi = Blah.objects.get(id=1)
filtered_or_anotated = Blah.blah(qs=hi)
# It's still a single object, but more filtered which of course is redundant.
print(filtered_or_anotated)

# Will show multiple objects since you're adding more filters
print(Blah.blah(Blah.objects.filter(id__in=[1,3,5])))

# Just for property clarity
print(hi.get_id) # 1

推荐阅读