Ordering from a method
Hay all, i have a simple model like this
def Article(models.Model):
upvotes = models.ManyToManyField(User, related_name='article_upvotes')
downvotes = models.ManyToManyField(User, related_name='article_downvotes')
def votes(self):
return self.upvotes - self.downvotes
With the view i can do things like
article_votes = article.votes
Am i able to order by the votes function? Something like
article = Article.objects.order_by('votes')
EDIT
I'm not near my dev system at the moment, so the syntax might b开发者_如何学Pythone a little off.
You can sort the list after the query returns the results:
article_votes = sorted(article.votes, key=lambda a: a.votes())
sorted
takes a list and sorts it. You can provide a custom function that takes an element and returns the value to use when comparing elements. lambda a: a.votes()
is an anonymous function that takes an article and returns the number of votes on the article.
If you are going to retrieve all the articles anyway, there's no downside to this solution. On the other hand, if you wanted only the top 10 articles by votes, then you're pulling all the articles from the db instead of letting the db do the sort, and only returning the top ten. Compared to a pure SQL solution, this is retrieving much more data from the database.
This is a faster version of what Ned Batchelder suggested - as it does the counting in the database:
articles = list(Article.objects.annotate(upvote_num=models.Count('upvotes'), downvote_num=models.Count('downvotes')))
articles.sort(key=lambda a: a.upvotes - a.downvotes)
You can also do this completely inside the database:
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
""")
-- but I'm not sure if the double join is a good idea in your case. Also, I'm not sure if all those DISCTINCTs are needed. It's quite likely that this query can be rewritten in some better way, but I don't have an idea at the moment..
精彩评论