2015-04-22 2 views
0

У меня есть модель с полем position = PositiveIntegerField(unique=True). Учитывая экземпляр этой модели, я хочу получить экземпляр со следующей самой высокой позицией (с учетом определенных фильтров). Если этот экземпляр является наивысшим, я хочу обернуть его в 0 и вернуть экземпляр с наименьшей позицией; если этот экземпляр является единственным, я хочу вернуться сам.Можно ли это свести к одному запросу?

Вот мой код:

count = Player.objects.count() 
return Player.objects.filter(game_id=self.game_id, is_alive=True).annotate(
    relative_position=(F('position') - self.position - 1 + count) % count 
).order_by('relative_position')[:1].get() 

(Причина в том, что + count отрицательное число по модулю положительный один отрицательный в SQL.)

Это требует двух запросов к базе данных. Я подозреваю, что это можно сделать только в одном запросе, используя annotate и Count, но я не понял, как скомпоновать такой запрос. Можно ли это сделать, и если да, то как?

ответ

0

Я обнаружил, что условные выражения запроса являются вещью в Django 1.8, что означало, что я мог бы отказаться от арифметических операций по модулю и сделать это:

return Player.objects.filter(game_id=self.game_id, is_alive=True).order_by(
    Case(When(position__gt=self.position, then=Value(0)), default=Value(1)), 
    'position' 
)[:1].get() 
0

Не всегда точно один запрос, но это, вероятно, превосходит 2 запросов и аннотаций:

players = Player.objects.filter(game_id=self.game_id, is_alive=True).order_by('position') 
try: 
    return players.filter(position__lt=self.position)[0] 
except IndexError: 
    return players.last() 
Смежные вопросы