开发者

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜