2015-07-22 4 views
2

Я пытаюсь присвоить звание командам на основе очков, полученных за несколько игр. Команда с большим количеством очков занимает больше места, и если команды имеют равное количество очков, команда с наименьшими играемыми играми занимает больше места. Команды могут иметь равный ранг.Добавление литеральных значений в QuerySet в Django

Поскольку Django (или SQLite) поддерживает функцию окна DENSE_RANK, я должен вычислить ранг в Python. Хотя, первоначально, я сделал это на экземплярах модели, возвращаемых all(), я решил, что должен добавить ранг в QuerySet, возвращенный annotate().order_by(), сохраняя при этом объект QuerySet, например, с get().

class TeamManager(models.manager): 
    @staticmethod 
    def add_ranking(qs): 
     # First, populate rows and rankings lists 
     # ... 
     # Then, add it to the query set 
     literal_selects = [] 
     for row_id, ranking in zip([row.id for row in rows], rankings): 
      literal_selects.append('SELECT {} AS "thing_id", {} AS ranking'.format(row_id, ranking)) 
     extra_from = "(" + " UNION ALL ".join(literal_selects) + ")" 

     return qs.extra(
      tables=[extra_from], 
      select={'ranking': 'ranking'}, 
      where=['team.id = thing_id']) 

    def ranked_list(self): 
     qs = self.model.objects.annotate(
      num_games=Count('team__score_set'), 
      total_points=Sum('team__score_set__points'), 
      # Ideally, I would calculate ranking here 
     ).order_by('-total_points') 

     return TeamManager.add_ranking(qs) 

Это не работает, потому что ORM Джанго adds double quotes вокруг «имен таблиц» в extra(table)

Есть ли другой способ добавить буквенные значения к уже существующей QuerySet, или я должен заменить вызов аннотировать с вызовом на raw(), а затем работать оттуда? Было бы очень жаль, потому что я только что вложил немалый кусок времени в понимание того, как перевести исходный необработанный SQL-запрос (с GROUP BY и все) в более удобный для Djangoeque способ делать вещи. Я бы хотел, чтобы Django выбрался из этого, вместо того, чтобы танцевать в моей собственной старой мелодии SQL.

+1

Неа, я думаю, вы должны использовать 'raw' ... более вариант«там»будет испечь этот запрос в вид, который может быть представлен как отдельная модель через http://django-postgres.readthedocs.org/en/latest/views.html – Anentropic

+1

Не настоящий ответ, но когда мне приходилось сталкиваться с подобными проблемами при расчете ранжирования, я закончил создание другой стол с «очками/баллами». Он также сделал запрос намного быстрее, когда мы зацикливались на некоторых больших таблицах. Поэтому, возможно, есть способ создать и использовать какую-то таблицу «заработанных очков». – WayBehind

+0

Опубликуйте свои models.py – schillingt

ответ

2

Вы можете добавить буквальное значение с Value:

qs = self.model.objects.annotate(
    num_games=Count('team__score_set'), 
    total_points=Sum('team__score_set__points'), 
    ranking=Value(42, output_field=IntegerField()) 
).order_by('-total_points') 
Смежные вопросы