Заказ по методу - PullRequest
       18

Заказ по методу

0 голосов
/ 24 ноября 2010

Слушай, у меня есть простая модель, подобная этой

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

С таким видом я могу делать такие вещи, как

article_votes = article.votes

Могу ли я сделать заказ с помощью функции голосования?Что-то вроде

article = Article.objects.order_by('votes')

РЕДАКТИРОВАТЬ

В данный момент я не нахожусь рядом с моей системой разработки, поэтому синтаксис может быть немного неправильным.

Ответы [ 2 ]

2 голосов
/ 24 ноября 2010

Вы можете отсортировать список после того, как запрос вернет результаты:

article_votes = sorted(article.votes, key=lambda a: a.votes())

sorted берет список и сортирует его. Вы можете предоставить пользовательскую функцию, которая принимает элемент и возвращает значение, которое будет использоваться при сравнении элементов. lambda a: a.votes() - это анонимная функция, которая принимает статью и возвращает количество голосов за статью.

Если вы все равно собираетесь получить все статьи, у этого решения нет недостатка. С другой стороны, если вы хотите получить только 10 лучших статей по голосам, то вы извлекаете все статьи из базы данных, вместо того, чтобы позволить этой базе выполнить сортировку, и возвращаете только первую десятку. По сравнению с чисто SQL-решением это позволяет получать гораздо больше данных из базы данных.

0 голосов
/ 25 ноября 2010

Это более быстрая версия того, что предложил Нед Бэтчелдер - поскольку он выполняет подсчет в базе данных:

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.Вполне вероятно, что этот запрос может быть переписан как-то лучше, но сейчас у меня нет идеи ..

...