Django Count () в нескольких аннотациях - PullRequest
38 голосов
/ 22 июля 2011

Скажем, у меня есть простая модель форума:

class User(models.Model):
    username = models.CharField(max_length=25)
    ...

class Topic(models.Model):
    user = models.ForeignKey(User)
    ...

class Post(models.Model):
    user = models.ForeignKey(User)
    ...

Теперь скажите, что я хочу увидеть, сколько тем и сообщений есть у каждого пользователя в подмножестве пользователей (например, их имя пользователя начинается с "ab").

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

User.objects.filter(username_startswith="ab")
            .annotate(posts=Count('post'))
            .values_list("username","posts")

Получено:

[('abe', 5),('abby', 12),...]

и

User.objects.filter(username_startswith="ab")
            .annotate(topics=Count('topic'))
            .values_list("username","topics")

Выход:

[('abe', 2),('abby', 6),...]

ОДНАКО , когда я пытаюсь аннотировать оба, чтобы получить один список, я получаю что-то странное:

User.objects.filter(username_startswith="ab")
            .annotate(posts=Count('post'))
            .annotate(topics=Count('topic'))
            .values_list("username","posts", "topics")

Выход:

[('abe', 10, 10),('abby', 72, 72),...]

Почему темы и сообщения умножаются вместе?Я ожидал этого:

[('abe', 5, 2),('abby', 12, 6),...]

Каков наилучший способ получить правильный список?

Ответы [ 2 ]

91 голосов
/ 03 июля 2012

Я думаю Count('topics', distinct=True) должен поступать правильно.Это будет использовать COUNT(DISTINCT topic.id) вместо COUNT(topic.id), чтобы избежать дублирования.

User.objects.filter(
    username_startswith="ab").annotate(
    posts=Count('post', distinct=True)).annotate(
    topics=Count('topic', distinct=True)).values_list(
    "username","posts", "topics")
0 голосов
/ 02 ноября 2011

Попробуйте добавить отличительные данные к вашему последнему набору запросов:

User.objects.filter(
    username_startswith="ab").annotate(
    posts=Count('post')).annotate(
    topics=Count('topic')).values_list(
    "username","posts", "topics").distinct()

См. https://docs.djangoproject.com/en/1.3/ref/models/querysets/#distinct для получения дополнительной информации, но в основном вы получаете дублирующиеся строки, потому что аннотации охватывают несколько таблиц.

...