0

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

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

我做了一个表教室,每个条目都有一个学生(外键)、操作(进入、离开)和日期。

我的问题是如何获取当前在里面的学生(即他们的输入操作的日期晚于他们的离开操作的日期,或者没有离开日期),以及如何指定一个日期范围来获取学生当时在教室里。


编辑:更好的想法我还应该补充一点,有不止一个教室。

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

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,因为有两个“进入”和一个“离开”。此外,我无法检查特定日期范围以查看哪些学生的入学日期晚于他们的离开日期。

4

2 回答 2

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)
于 2010-01-22T16:32:32.047 回答
1

Django 为您提供了Q()andF()运算符,它们非常强大,足以应付大多数情况。但是,我认为这对您来说还不够。让我们在 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。但是,如果您使用SQLiteMySQL作为数据库后端(很可能是),则WITH可能不支持用于创建临时视图的关键字之类的内容,并且查询只会变得更加复杂。可能有一个更简单的版本,但我并没有真正看到它。

我的观点是,当你达到这种复杂程度,F()并且Q()变得不适合这项工作的工具时,所以我宁愿建议你手动编写 SQL 代码并在 Django 中使用 Raw SQL

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

顺便说一句,在同一区间内获取教室里的人的查询就像那个查询一样,但是您所要做的就是将最后一次离开 ts限制在区间的开头,最后一次进入 ts到结尾的区间。

于 2010-01-23T00:14:34.727 回答