2013-04-04 7 views
1

Я действительно борюсь за это. Мне нужно уметь сортировать пользователя по количеству положительных голосов, полученных в их комментарии.Django sql order by

У меня есть userprofile таблицы, комментарий таблицы и таблица likeComment. В комментарии к таблице есть внешний ключ для пользователя-пользователя, а таблица likeComment имеет внешний ключ для комментария. Чтобы получить число положительных голосов пользователь получил я:

LikeComment.objects.filter(Q(type = 1), Q(comment__user=user)).count() 

Теперь я хочу, чтобы иметь возможность получить все пользователи, отсортированные по те, которые имеют самые положительные голоса. Как мне это сделать ? Я пытался использовать дополнительные и JOIN, но это никуда не денется.

Спасибо

ответ

2

Это звучит, как вы хотите, чтобы выполнить фильтр аннотацию:

class User(models.Model): 
    pass 

class Comment(models.Model): 
    user = models.ForeignKey(User, related_name="comments") 

class Like(models.Model): 
    comment = models.ForeignKey(Comment, related_name="likes") 
    type = models.IntegerField() 

users = User \ 
    .objects \ 
    .all() 
    .extra(select = { 
     "positive_likes" : """ 
     SELECT COUNT(*) FROM app_like 
     JOIN app_comment on app_like.comment_id = app_comment.id 
     WHERE app_comment.user_id = app_user.id AND app_like.type = 1 """}) 
    .order_by("positive_likes") 
+0

Спасибо Тимми, я получал орехи и разрешаю сделать запрос! Теперь, когда я делаю это, я получаю ошибку БД: синтаксическая ошибка в или рядом с «SELECT» LINE 8: SELECT COUNT (*) FROM axiom_alto_likecomment –

+0

Я понял! это было из-за аннотации по какой-то причине, я не могу комментировать и добавить, поэтому я поместил все в extraa ^^ еще раз спасибо –

1

models.py

class UserProfile(models.Model): 
    ......... 

    def like_count(self): 
     LikeComment.objects.filter(comment__user=self.user, type=1).count() 

views.py

def getRanking(anObject): 
    return anObject.like_count() 

def myview(request): 
    users = list(UserProfile.objects.filter()) 
    users.sort(key=getRanking, reverse=True)  
    return render(request,'page.html',{'users': users}) 
+0

Это решение является правильным, но оно приведет к высокой нагрузке, если сайт получает большое количество пользователей или запросов за минуту. – Igor

+0

@Igor существует множество способов уменьшить эту нагрузку, если вы хотите. Он может использовать разбиение на страницы, которые загружают 10 пользователей на страницу. Он также может получить только 10 или 20 пользователей, остальные пользователи могут их искать. Проблемы имеют много решений, если вы действительно этого хотите. – catherine

+0

Я делал это в начале, но я думаю, что дополнительная скорость быстрее ^^ Спасибо, в любом случае, потому что вы решили другую проблему, я имел ^^ –

0

Timmy's suggestion to use a subquery - p грамотно простейший способ решить эту проблему, но подзапросы почти никогда не выполняются, а также объединяются, поэтому, если у вас много пользователей, вы можете обнаружить, что вам нужна более высокая производительность.

Так, повторное использование модели Тиая:

class User(models.Model): 
    pass 

class Comment(models.Model): 
    user = models.ForeignKey(User, related_name="comments") 

class Like(models.Model): 
    comment = models.ForeignKey(Comment, related_name="likes") 
    type = models.IntegerField() 

запроса вы хотите выглядит в SQL:

SELECT app_user.id, COUNT(app_like.id) AS total_likes 
FROM app_user 
LEFT OUTER JOIN app_comment 
      ON app_user.id = app_comment.user_id 
LEFT OUTER JOIN app_like 
      ON app_comment.id = app_like.comment_id AND app_like.type = 1 
GROUP BY app_user.id 
ORDER BY total_likes DESCENDING 

(Если фактическая User модель имеет больше полей, чем просто id, затем вам необходимо будет включить их в статьи SELECT и GROUP BY.)

Объектно-реляционное сопоставление Django система не предоставляет способ выражения этого запроса. (Насколько я знаю, и я был бы очень рад, если вам будет сказано иначе) - это только поддержка агрегации в одном соединении, а не через два объединения, как здесь.) Но когда ORM не совсем подходит к работе, вы всегда можно запустить raw SQL query, как это:

sql = ''' 
    SELECT app_user.id, COUNT(app_like.id) AS total_likes 
    # etc (as above) 
''' 
for user in User.objects.raw(sql): 
    print user.id, user.total_likes 
0

Я считаю, что это может быть достигнуто с QuerySet Джанго:

User.objects.filter(comments__likes__type=1)\ 
    .annotate(lks=Count('comments__likes'))\ 
    .order_by('-lks') 

Единственная проблема в том, что этот запрос будет не хватать пользователей 0 любит. Код от @ gareth-rees, @ timmy-omahony и @Catherine будет включать также пользователей с 0-значным рейтингом.

+0

спасибо, что я использовал @ timmy-omahony, и это сработало. спасибо –