2016-12-14 4 views
1

Ich habe eine folgende Modelle:Django ManyToMany Abfrage seltsame Verhalten

class Post(Model): 
    word = TextField() 
    subscribers = ManyToManyField(User, related_name='subscribed', through='Subscription') 

class Subscription(Model): 
    post = ForeignKey(Post) 
    subscriber = ForeignKey(User) 
    date_subscribed = DateTimeField(default=timezone.now) 

    class Meta: 
     ordering = ('-date_subscribed',) 
     unique_together = (('post', 'subscriber')) 

Was ich tun möchte, ist alle Beiträge zu wählen und bestellen sie nach der Anzahl der Teilnehmer, und wenn die Anzahl der Teilnehmer gleich ist, um durch zuletzt date_subscribed.

Meine Eingangsdaten:

post1 = Post(text="post1") 
post2 = Post(text="post2") 
post3 = Post(text="post3") 
post4 = Post(text="post4") 

user1 = User(username="user1") 
user2 = User(username="user2") 
user3 = User(username="user3") 
user4 = User(username="user4") 

Subscription.objects.create(post=post1, user=user1) 
Subscription.objects.create(post=post2, user=user1) 
Subscription.objects.create(post=post3, user=user1) 
Subscription.objects.create(post=post3, user=user2) 
Subscription.objects.create(post=post3, user=user3) 
Subscription.objects.create(post=post3, user=user4) 
Subscription.objects.create(post=post4, user=user1) 
Subscription.objects.create(post=post4, user=user2) 
Subscription.objects.create(post=post4, user=user3) 

Diese Abfrage funktioniert wie erwartet, aber es bestellen nicht von date_subscribed:

Post.objects.annotate(s_count=Count('subscribers')).order_by('-s_count') 

Wenn ich schreibe:

Post.objects.annotate(s_count=Count('subscribers')).order_by('-s_count', '-subscription__date_subscribed') 

Ich habe seltsame Ergebnisse und ich verstehe dieses Verhalten nicht wirklich. Für obige Daten gibt es genau alle Posts mit s_count=1 aus.

Warum s_count ist 1? Und auch, wie man zuletzt richtig bestellt date_subscribed?

UPD: Noch eine Frage. Warum gibt Post.objects.annotate(s_count=Count('subscribers')).order_by‌​('-s_count', '-subscription__date_subscribed').count() 4 statt Anzahl der Zeilen im Abonnement?

Antwort

1

Da Subscription ist eine durch Tabelle für m2m Beziehung zwischen den Post und Subscriber, wenn Sie auf einem Feld von Subscription Modell bestellen selbst, alle Beiträge als einzelne Zeilen in der Ergebnismenge erscheinen, und das ist, warum Sie s_count=1 bekommen, weil jeder Pfosten mit einem bestimmten Teilnehmer ist einzigartig.

Sie müssen die Post Objekte mit der neuesten date_subscribed aller subscribers und dann, um auf kommentierten Feld mit Anmerkungen versehen:

posts = Post.objects.annotate(
      s_count=Count('subscribers'), 
      s_date_max=Max('subscription__date_subscribed') 
     ).order_by('-s_count', '-s_date_max') 

UPDATE für die nächste Frage:

Wenn Sie count() Methode wird es die Nummer Posts zurückgeben. Sie können sehen, dass es sich von der Zählung unterscheidet, die Sie von len(queryset.values_list('s_count', 'subscription__date_subscribed')) erhalten, da zu diesem Zeitpunkt die einzelnen Werte für Datumsangaben in der Ergebnismenge abgerufen wurden.

+1

Ziemlich einfach. Vielen Dank. –

+0

Ich bin froh, dass ich helfen kann. – AKS

+0

Noch eine Frage. Warum Post.objects.annotate (s_count = Anzahl ('Abonnenten')). ​​Order_by ('- s_count', '-subscription__date_subscribed'). Count() gibt 4 statt Anzahl der Zeilen im Abonnement? –