Это более быстрая версия того, что предложил Нед Бэтчелдер - поскольку он выполняет подсчет в базе данных:
articles = list(Article.objects.annotate(upvote_num=models.Count('upvotes'), downvote_num=models.Count('downvotes')))
articles.sort(key=lambda a: a.upvotes - a.downvotes)
Вы также можете сделать это полностью внутри базы данных:
articles = Article.objects.raw("""
SELECT DISTINCT id from articles_article,
COUNT(DISTINCT upv) AS num_upvotes,
COUNT(DISTINCT downv) AS num_downvotes,
(num_upvotes - num_downvotes) AS score
INNER JOIN [article_user_upvotes_m2m_table_name] AS upv
ON upv.article_id = id
INNER JOIN [article_user_downvotes_m2m_table_name] AS downv
ON downv.article_id = id
GROUP BY id
ORDER BY score
""")
- но я не уверен, что двойное соединение - хорошая идея в вашем случае.Кроме того, я не уверен, нужны ли все эти DISCTINCT.Вполне вероятно, что этот запрос может быть переписан как-то лучше, но сейчас у меня нет идеи ..