Я запутался в том, как Different () работает с запросами Django - PullRequest
1 голос
/ 24 ноября 2011

У меня есть этот запрос:

checkins = CheckinAct.objects.filter(time__range=[start, end], location=checkin.location)

Это прекрасно подходит для того, чтобы сообщить мне, сколько проверок произошло в моем диапазоне дат для определенного местоположения.Но я хочу знать, сколько проверок было сделано уникальными пользователями.Итак, я попробовал это:

checkins = CheckinAct.objects.filter(time__range=[start, end], location=checkin.location).values('user').distinct()

Но это не работает, я получаю пустой массив.Есть идеи, почему?

Вот моя модель CheckinAct:

class CheckinAct(models.Model):
    user = models.ForeignKey(User)
    location = models.ForeignKey(Location)
    time = models.DateTimeField()

---- Обновление ------ Итак, теперь я обновил свой запрос, чтобы он выглядел так:

 checkins = CheckinAct.objects.values('user').\
                            filter(time__range=[start, end], location=checkin.location).\
                            annotate(dcount=Count('user'))

Но я все еще получаю несколько объектов назад, которые имеют одного и того же пользователя, например:

 [{'user': 15521L}, {'user': 15521L}, {'user': 15521L}, {'user': 15521L}, {'user': 15521L}]

---- Обновление 2 ------ Вот еще кое-чтоЯ пытался, но я все еще получаю много идентичных пользовательских объектов при регистрации объекта checkins.

checkins = CheckinAct.objects.filter(
                    time__range=[start, end],
                    location=checkin.location,
                ).annotate(dcount=Count('user')).values('user', 'dcount')
        logger.info("checkins!!! : " + str(checkins))

Регистрирует следующее:

checkins!!! : [{'user': 15521L}, {'user': 15521L}, {'user': 15521L}]

Обратите внимание, что существует 3 экземпляра.одного и того же объекта пользователя.Это работает правильно или нет?Есть ли другой способ прочитать то, что возвращается в объекте dict?Мне просто нужно знать, сколько уникальных пользователей зарегистрировались в этом конкретном месте за указанный промежуток времени.

Ответы [ 3 ]

1 голос
/ 28 ноября 2011

Ответ на самом деле правильный в Django документах .К сожалению, очень мало внимания уделяется важности той части, которая вам нужна;так что это по понятным причинам пропущено.(Прочитайте немного к части, касающейся Item с.)

Для вашего случая использования следующее должно дать вам именно то, что вы хотите:

checkins = CheckinAct.objects.filter(time__range=[start,end], location=checkin.location).\
                              values('user').annotate(checkin_count=Count('pk')).order_by()

ОБНОВЛЕНИЕ

Исходя из вашего комментария, я думаю, что вопрос о том, чего вы хотели достичь, был запутан все время.Вышеприведенный запрос дает вам список того, сколько раз каждый пользователь регистрировался в определенном месте, без повторяющихся пользователей в указанном списке.Теперь кажется, что вы действительно хотели количество уникальных пользователей, которые зарегистрировались в одном конкретном месте.Чтобы получить это, используйте следующее (что в любом случае намного проще):

User.objects.filter(checkinat__location=location).distinct().count()

ОБНОВЛЕНИЕ для поддержки без поддержки

checkin_users = [(c.user.pk, c.user) for c in CheckinAct.objects.filter(location=location)]
unique_checkins = len(dict(checkin_users))

Это работает по принципучто у dict есть уникальные ключи.Поэтому, когда вы преобразуете список кортежей в dict, вы получаете список уникальных пользователей. Но , это сгенерирует 1 * N запросов, где N - общее количество проверок (один запрос каждый раз, когда используется атрибут user. Обычно я бы делал что-то вроде .select_related('user'), нодля этого также требуется JOIN, который, по-видимому, отсутствует. JOIN, не поддерживаемые, выглядит как огромный недостаток по отношению к non-rel, если это правда, но если это так, то это будет единственный вариант.

0 голосов
/ 24 ноября 2011
checkins = CheckinAct.objects.values('user').\
                        filter(time__range=[start, end], location=checkin.location).\
                        annotate(dcount=Count('user'))

Если я не ошибаюсь, не будет ли значение, которое вы хотите, во входных данных как "dcount"?В результате, это не просто отбрасывается, когда вы решаете вывести только пользовательское значение?

Можете ли вы сказать мне, что происходит, когда вы пытаетесь это сделать?

checkins = CheckinAct.objects.values('user').\
                        filter(time__range=[start, end], location=checkin.location).\
                        annotate(Count('user')).order_by()

(Последнееorder_by - очистить любой встроенный порядок, который у вас уже может быть на уровне модели - не уверен, что у вас есть что-то подобное, но не мешает спросить ...)

0 голосов
/ 24 ноября 2011

Вы не хотите DISTINCT.Вы действительно хотите, чтобы Django сделал что-то, что в итоге даст вам предложение GROUP BY.Вы также правы в том, что ваше окончательное решение - объединить annotate() и values(), как обсуждено в документации Django .

Что вы хотите сделать, чтобы получить свои результаты, это использоватьСначала annotate, а затем values, например:

CheckinAct.objects.filter(
    time__range=[start, end],
    location=checkin.location,
).annotate(dcount=Count('user').values('user', 'dcount')

Документы Django по ссылке, которую я дал вам выше, показывают аналогично сконструированный запрос (за исключением аспекта filter, который я добавил дляваш случай в нужном месте), и обратите внимание, что это «теперь даст один уникальный результат для каждого [акта регистрации]; однако в выходных данных будут возвращаться только аннотации [user] и [dcount]».(Я отредактировал предложение, чтобы оно соответствовало вашему случаю, но принцип тот же).

Надеюсь, это поможет!

...