Фильтр Django через вычисленное значение 2 Foreignkeys - PullRequest
1 голос
/ 16 мая 2019

Примите во внимание следующее:

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 () Iнужно уметь фильтровать это качество, например, все бойцы, у которых 50% <качество <80%.Я хочу, чтобы моя база данных Postgres заработала. </p>

Мне кажется, что это возможно через Aggregate, но я не могу понять, как ...

1 Ответ

2 голосов
/ 16 мая 2019

Вы можете .annotate(..) бойцов с этой метрикой качества, а затем фильтровать с заданным диапазоном, например:

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

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

Необходимо distinct=True, так как в противном случае качество всегда 1: действительно, так как мы делаем два СОЕДИНЕНИЯ и подсчитываем id с View с и id с Win с, но эти цифры всегда совпадают.

Таким образом, quality__range=(0.5, 0.8) будет фильтровать аннотацию quality с помощью поиска __range с 0.5 нижней границей и 0.8 верхней границей (оба включительно).

ExpressionWrapper(..., outputField=FloatField()) необходим для того, чтобы Django понимал, что quality - это число с плавающей точкой, в противном случае он преобразует 0.5 и 0.8 в int и, таким образом, проверяет значения между 0 и 0.

...