这可能是一个很容易发现的错误,但我不是最熟悉Django查询的人,所以我花了几个小时努力解决这个问题.

我有一个Django Rest应用程序,在那里我有两个模型:

class Student(models.Model):
    name = models.CharField(max_length=20)
    status = models.CharField(max_length=4, blank=True, default="UNK", choices=STATUS_TYPES)
    started_date = models.DateTimeField(null=False, auto_now_add=True)


class StudentStatusHistory(BaseTimestampModel):
    """Table of status changes for Students"""
    student = models.ForeignKey(
        "core.Student", on_delete=models.CASCADE, related_name="StatusHistory"
    )
    status = models.CharField(
        max_length=4, blank=True, default="UNK", choices=STATUS_TYPES
    )
    created_on = models.DateTimeField(null=False, auto_now_add=True)

供参考:

STATUS_TYPES = [("UNK", "Unknown"), (“PASS", “Passed"), (“FAIL", “Failed")]

我正在try 编写一个查询,以计算在一周或更短的时间窗口内有多少学生的状态更改为Pass.

例如,如果Student.started_date2023-07-15 12:22:22,StudentStatusHistory.created_on字段是2023-07-21 12:22:22,对于一个Student.status等于PASS的学生,我想计算这个学生,因为他们在不到一周的时间内通过了考试(在本例中是6天).

另外,我只想计算当月开始的学生的这一数字.

到目前为止,我所拥有的是:

current_month_start = datetime(datetime.today().year, datetime.today().month, 1)

# Subquery to filter StudentStatusHistory objects for each Student object within a week or less
pass_within_week_subquery = StudentStatusHistory.objects.filter(
            student_id=OuterRef(“pk"),
            status="PASS",
            created_on__range=(OuterRef("started_date"), OuterRef(“started_date") + timedelta(weeks=1))
        )

# Subquery to filter Student objects created within the current month
student_within_month_subquery = Student.objects.filter(
            started_date__gte=current_month_start,
            pk=OuterRef(“pk"),
        )

# Main queryset to annotate Student objects with pass_within_week count
student_objects_with_pass_within_week = Student.objects.annotate(
            pass_within_week_count=Subquery(
                pass_within_week_subquery.annotate(count_pass_within_week=Count("pk")).values(“count_pass_within_week"),
                output_field=IntegerField()),
            is_within_month=Exists(student_within_month_subquery),
        )

# Count the number of student objects that satisfy the condition
count_student_pass_within_week = student_objects_with_pass_within_week.filter(pass_within_week_count__gt=0,
is_within_month=True).count()

return Response(data= count_student_pass_within_week)

(我不确定python格式有什么问题,但请忽略或编辑这一部分)

一切似乎都很顺利,直到关于返回错误的计数的最后一行:

ValueError: This queryset contains a reference to an outer query and may only be used in a subquery.

我读了很多关于OuterRef、子查询等的内容,我以为在主查询集中使用它们可以解决这个问题,但显然不能.

有什么主意吗?

推荐答案

我认为您可以使用以下命令更简单地完成此操作:

from datetime import timedelta

from django.db.models import F

Student.objects.filter(
    StatusHistory__status='PASS',
    StatusHistory__created_on__range=(
        F('started_date'),
        F('started_date') + timedelta(weeks=1),
    ),
).distinct().count()

因此,我们对Student进行筛选,以仅保留具有status='PASS'的相关StatusHistorycreated_on,以及时间范围started_datestarted_date以及一周的created_on.然后,我们计算与此匹配的distinctStudent.如果在该周内将状态多次设置为PASS,我们需要使用.distinct() [Django-doc]来防止对学生进行多次计数.


Note:related_name=… [Django-doc] 是反向获取相关对象的管理器的名称.因此 通常ForeignKeyManyToManyFieldrelated_nameplural, 例如status_changes而不是StatusHistory.

Mysql相关问答推荐

完全相同的A B表达在SQL中的不同上下文中意外返回不同的结果

S优化联接更新的最佳方式是什么?

从表中 Select 具有不同顺序的列

使用不同的 where 列进行子 Select

如何对 varchar() 数据值使用聚合窗口函数?

即使在某些表中不匹配,如何从 MySQL 中的多个表中 Select 所有记录

for each 查询设置 MySQL @@session.time_zone 而不是 CONVERT_TZ 的缺点?

为两个中的每一个 Select 最大和最小传递条件

MySQL,递归 CTE.它如何以这种句法形式工作?

如何在 MySQL 中使用从 SELECT IF 返回的布尔值

为什么这个 NOT NULL 到 NULL 迁移会触发大量 I/O 操作?

在 MySQL 中使用三个表进行计算

mysql - 如何加入表中的动态列

mysql从另一个表中 Select 不相等的值

提高mysql导入速度

MySQL PHP - Select WHERE id = array()?

MySQL ORDER BY rand(),名称为 ASC

第 1 行的 CSV 输入中的列数无效错误

MySQL:唯一字段需要是索引吗?

在 MySQL 的 LIMIT 子句中使用变量