基于列内容检索Django查询集中的唯一结果

时间:2010-01-22 16:18:36

标签: django django-queryset

我不确定标题是否有意义,但这是问题。

背景:我想跟踪哪些学生进入和离开教室,以便在任何时候我都能知道谁在教室里。我还想跟踪,例如,学生进入课堂的次数。这是一个假设的例子,非常接近我想要实现的目标。

我制作了一个桌子课堂,每个条目都有学生(ForeignKey),动作(进入,离开)和日期。

我的问题是如何让当前进入的学生(即他们的进入行动'日期晚于离开行动的日期,或者没有休假日期),以及如何指定日期范围让当时在教室里的学生。


编辑:更好的想法我还应该补充说,有多个教室。

我的第一次尝试是这样的:

students_in = Classroom.objects.filter(classroom__exact=1, action__exact='1')
students_out = Classroom.objects.filter(classroom__exact=1, action__exact='0').values_list('student', flat=True)
students_now = students_in.exclude(student__in=students_out)

如果action == 1,则表示0已经结束。

但是,一旦学生离开教室并重新进入,这就会提供错误的数据。她在students_now查询集中列出了两次,因为有两个'进入'和一个'离开'。此外,我无法查看具体的日期范围,以查看哪些学生的入学日期晚于出发日期。

2 个答案:

答案 0 :(得分:1)

要根据其他字段的值检查字段,请使用F()运算符。

from django.db.models import F
students_in_classroom_now = Student.objects.filter(leave__gte=F('enter'))

让所有学生在某个时间进入房间:

import datetime
start_time = datetime.datetime(2010, 1, 21, 10, 0, 0) # 10am yesterday
students_in_classroom_then = Student.objects.filter(enter__lte=start_time,
                                                    leave__gte=start_time)

答案 1 :(得分:1)

Django为您提供Q()F()运算符,这些运算符非常强大且足以满足大多数情况。但是我不认为这对你来说已经足够了。让我们在SQL级别考虑您的问题。

我们有类似表Classroom ( action, ts, student_id )的东西。为了知道现在哪些学生在教室,我们必须做出类似的事情:

with ( /* temporary view with last user_action */
  select action, max(ts) xts, student_id
  from Classroom
  group by action, student_id
) as uber_table
select a.student_id student_id
from uber_table a, uber_table b
where a.action = 'enter'
  /* either he entered and never left */
  and (a.student_id not in (select student_id from uber_table where action = 'leave')
    /* or he left before he entered again, so he's still in */
    or (a.student_id = b.student_id and b.action = 'leave' and b.xts < a.xts))

我相信这是标准的SQL。但是,如果您使用 SQLite MySQL 作为数据库后端(很可能是您),那么用于创建临时视图的WITH关键字等内容可能不是不支持,查询将变得更加复杂。可能有一个更简单的版本,但我真的没有看到它。

我的观点是,当你达到这种复杂程度时,F()Q()成为工作的不充分工具,所以我宁愿建议你手工编写SQL代码使用Raw SQL in Django

如果您需要使用更常见的数据访问API,您应该以 @Daniel Roseman 暗示的方式重写数据模型。

顺便说一句,在相同的时间间隔内获取教室内人员的查询就像那个,但你所要做的就是将最后的离开ts 限制在开头间隔和最后一个输入ts 到间隔结束。