Получение уникальных результатов в наборе запросов Django на основе содержимого столбца - PullRequest
0 голосов
/ 22 января 2010

Я не уверен, имеет ли название смысл, но вот вопрос.

Контекст: я хочу отслеживать, какие учащиеся входят и выходят из класса, чтобы в любой момент я мог знать, кто находится в классе. Я также хочу отслеживать, например, сколько раз ученик входил в класс. Это гипотетический пример, который очень близок к тому, чего я хочу достичь.

Я создал таблицу Classroom, и у каждой записи есть Студент (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 ]

1 голос
/ 23 января 2010

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 вручную и использовать Необработанный SQL в Django .

Если вам нужно использовать более распространенные API доступа к данным, вам, вероятно, следует переписать вашу модель данных так, как подразумевается @ Daniel Roseman .

Кстати, запрос на получение людей, которые были в классе в одном интервале, похож на этот, но все, что вам нужно сделать, это ограничить последний , оставив началом начала интервал и последний введите ts до конца интервала.

1 голос
/ 22 января 2010

Чтобы проверить поле на основе значения другого поля, используйте оператор 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...