【问题标题】:Retrieving unique results in Django queryset based on column contents根据列内容检索 Django 查询集中的唯一结果
【发布时间】:2010-01-22 16:18:36
【问题描述】:

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

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

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

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


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

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

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

【问题讨论】:

    标签: django django-queryset


    【解决方案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)
    

    【讨论】:

    • 谢谢,我会测试它并告诉你。因此,您建议使用两列(进入和离开),而不是为操作设置一列。在这种情况下,在管理员中如何确保至少有一个不为空。
    【解决方案2】:

    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。但是,如果您使用 SQLiteMySQL 作为数据库后端(很可能是),那么用于创建临时视图的 WITH 关键字可能不是支持,查询将变得更加复杂。可能有一个更简单的版本,但我并没有真正看到它。

    我的意思是,当您达到这种复杂程度时,F()Q() 成为不适合这项工作的工具,因此我宁愿建议您手动编写 SQL 代码并使用 Raw SQL in Django .

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多