Django通过2个外键的计算值进行过滤

时间:2019-05-16 16:36:55

标签: django django-models filter foreign-keys

请考虑以下内容:

class Fighter(models.Model):
   ...
   #a bunch of fields

class View(models.Model):
   fighter = models.ForeignKey(Fighter,on_delete=models.CASCADE, related_name="views")
   viewer = models.ForeignKey(User,on_delete=models.PROTECT, related_name="viewed") #User.viewed.all() returns all View objects of the Fighters the user viewed

class Clash(models.Model):
   win_fighter = models.ForeignKey(Fighter,on_delete=models.SET_NULL, related_name="wins")
   loss_fighter = models.ForeignKey(Fighter,on_delete=models.SET_NULL, related_name="losses")

这里的关键是fighter_quality = wins / views = Fighter.wins.all()。count()/ Fighter.views.all()。count() 我需要能够过滤这种质量,例如所有50%<质量<80%的战斗机。我希望我的Postgres DB能够完成工作。

我觉得应该可以通过Aggregate来实现,但不知道如何...

1 个答案:

答案 0 :(得分:2)

您可以.annotate(..)使用该质量指标的战斗机,然后按照给定的范围进行过滤,例如:

from django.db.models import Count, ExpressionWrapper, FloatField

Fighter.objects.annotate(
    quality=ExpressionWrapper(
        Count('wins', distinct=True)/Count('views', distinct=True),
        output_field=FloatField()
    )
).filter(
    quality__range=(0.5, 0.8)
)

distinct=True是必需的,因为否则质量始终为1:实际上,由于我们进行了两个JOIN,并且我们计算了id中的Viewid中的Win个,但这些数字始终匹配。

因此,quality__range=(0.5, 0.8)将使用__range查找(其中下限为quality,上限为0.5(包括两者)筛选0.8注释

ExpressionWrapper(..., outputField=FloatField())是必需的,以便Django理解quality是浮点数,否则它将将0.50.8转换为int,因此检查00之间的值。