Django Count () dans les annotations multiples

disons que j'ai un modèle de forum simple:

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)
    ...

Maintenant, dites que je veux voir combien de sujets et de messages chaque utilisateur de sous-ensemble des utilisateurs a (par exemple, leur nom d'utilisateur commence par "ab").

donc si je fais une requête pour chaque poste et sujet:

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

Yeilds:

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

et

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

rendements:

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

cependant, quand j'essaie d'annoter les deux pour obtenir une liste, j'obtiens quelque chose étrange:

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

rendements:

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

Pourquoi les sujets et messages multipliés? Je m'attendais à ceci:

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

Quelle serait la meilleure façon d'obtenir la bonne liste?

33
demandé sur user749618 2011-07-22 23:40:59

2 réponses

je pense que Count('topics', distinct=True) devrait faire la bonne chose. Qui va utiliser COUNT(DISTINCT topic.id) au lieu de COUNT(topic.id) pour éviter les doublons.

User.objects.filter(
    username_startswith="ab").annotate(
    posts=Count('post', distinct=True)).annotate(
    topics=Count('topic', distinct=True)).values_list(
    "username","posts", "topics")
80
répondu fhahn 2012-07-03 20:40:59

essayez d'ajouter distinct à votre dernier queryset:

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

voir https://docs.djangoproject.com/en/1.3/ref/models/querysets/#distinct pour plus de détails, mais en gros vous obtenez des lignes dupliquées parce que les annotations couvrent plusieurs tables.

1
répondu Jeremy Lewis 2011-11-02 11:06:58