【问题标题】:Django Annotation Count with Subquery & OuterRef带有子查询和 OuterRef 的 Django 注释计数
【发布时间】:2022-01-19 20:52:27
【问题描述】:

我正在尝试为测验创建一个高分统计表/列表,该表/列表应该显示对要被猜测的人的正确猜测的百分比(或总数)。为了进一步详细说明,这些是使用的模型。

测验模型:

class Quiz(models.Model):
participants = models.ManyToManyField(
    User,
    through="Participant",
    through_fields=("quiz", "correct_user"),
    blank=True,
    related_name="related_quiz",
)
fake_users = models.ManyToManyField(User, related_name="quiz_fakes")
user_quizzed = models.ForeignKey(
    User, related_name="user_taking_quiz", on_delete=models.CASCADE, null=True
)
time_started = models.DateTimeField(default=timezone.now)
time_end = models.DateTimeField(blank=True, null=True)
final_score = models.IntegerField(blank=True, default=0)

这个模型也有一些属性;我认为它们与手头的问题无关。

参与者模型:

class Participant(models.Model):  # QuizAnswer FK -> QUIZ
guessed_user = models.ForeignKey(
    User, on_delete=models.CASCADE, related_name="clicked_in_quiz", null=True
)
correct_user = models.ForeignKey(
    User, on_delete=models.CASCADE, related_name="solution_in_quiz", null=True
)
quiz = models.ForeignKey(
    Quiz, on_delete=models.CASCADE, related_name="participants_in_quiz"
)

@property
def correct(self):
    return self.guessed_user == self.correct_user

为了迭代我正在尝试做的事情,我将尝试解释我认为这应该如何工作:

  1. 对于User.objects.all() 中的User,查找user.id 等于correct_user 的所有participant 对象(来自participant 模型)
  2. 对于每个participantobject,评估correct_user==guessed_user
  3. 对每个participant 对象求和,其中上述比较为TrueUser,由字段sum_of_correct_guesses 表示
  4. 返回一个查询集,包括所有带参数的用户 [User, sum_of_correct_guesses]

^现在理想情况下应该是percentage_of_correct_guesses,但这是事后的想法,通过sum_of_correct_guesses / sum n 次该人的猜测应该很容易改变。

现在我什至为一个人制作了一些伪代码,以便向自己大致说明它应该如何使用 python 算术工作

# PYTHON PSEUDO QUERY ---------------------
person = get_object_or_404(User, pk=3)  # Example-person
y = Participant.objects.filter(
    correct_user=person
)  # Find participant-objects where person is used as guess
y_corr = []  # empty list to act as "queryset" in for-loop

for el in y:  # for each participant object
    if el.correct:  # if correct_user == guessed_user
        y_corr.append(el)  # add to queryset
y_percentage_corr = len(y_corr) / len(y)  # do arithmetic division
print("Percentage correct: ", y_percentage_corr)  # debug-display
# ---------------------------------------------

我尝试过的(到目前为止没有成功)是使用带有 Count()Q 对象的 ExtensionWrapper:

percentage_correct_guesses = ExpressionWrapper(
Count("pk", filter=Q(clicked_in_quiz=F("id")), distinct=True)
/ Count("solution_in_quiz"),
output_field=fields.DecimalField())

all_users = (
User.objects.all().annotate(score=percentage_correct_guesses).order_by("score"))

非常感谢任何有关如何执行此操作的帮助或资源指示:))

【问题讨论】:

    标签: django django-annotate django-aggregation django-subquery


    【解决方案1】:

    我在四处寻找相关问题时找到了答案: Django 1.11 Annotating a Subquery Aggregate

    我所做的是:

    • 使用指向UserOuterRef()创建一个过滤器,并检查User是否与correct_person相同,以及guessed_personcorrect_person之间的比较,输出一个值correct_user在过滤器接受的所有元素的查询集中。
    • 对过滤后的查询集中出现correct_user 的次数进行注释计数。
    • 根据annotated-count对User进行注解,这才是真正驱动整个操作的注解。请注意OuterRef()Subquery 如何用于告诉过滤器哪个用户应该是correct_user

    下面是我使用的代码 sn-p,它看起来与上面链接问题中的答案非常相似:

    from django.db.models import Count, OuterRef, Subquery, F, Q
    
    crit1 = Q(correct_user=OuterRef('pk'))
    crit2 = Q(correct_user=F('guessed_user'))
    compare_participants = Participant.objects.filter(crit1 & crit2).order_by().values('correct_user')
    count_occurrences = compare_participants.annotate(c=Count('*')).values('c')
    most_correctly_guessed_on = (
        User.objects.annotate(correct_clicks=Subquery(count_occurrences))
        .values('first_name', 'correct_clicks')
        .order_by('-correct_clicks')
    )
    return most_correctly_guessed_on
    

    感谢Oli,这非常有效。

    【讨论】:

      猜你喜欢
      • 2018-04-16
      • 2021-09-17
      • 2017-10-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-14
      • 2019-08-03
      • 1970-01-01
      • 2019-06-06
      相关资源
      最近更新 更多