Django模型查询最接近的整数匹配

时间:2015-03-27 16:12:45

标签: python django django-queryset

我得到了一些具有不同评级字段值的Django模型对象:

puzzles_rating = [0, 123, 245, 398, 412, 445, 556, 654, 875, 1000]
    for rating in puzzles_rating:
        puzzle = Puzzle(rating=rating)
        puzzle.save()

现在,对于user_rating = 500,我想选择评分最接近的拼图。在上面的情况下,它应该是#6拼图,评级为445。

问题是我不能这样做:

puzzle = Puzzle.objects.filter(rating__lte=user_rating).order_by('-rating')[0]

因为,一般来说,我最接近的匹配等级可能高于目标等级。

是否有方便的方法从两个方向查询最接近的匹配?

2 个答案:

答案 0 :(得分:8)

您可以使用extra方法:

puzzle = Puzzle.objects.extra(select={
    'abs_diff': 'ABS(`rating` - %s)',
}, select_params=(rating,)).order_by('abs_diff').first()

从Django 1.8开始,你不需要编写原始SQL,你可以使用Func

from django.db.models import Func, F

    puzzle = Puzzle.objects.annotate(abs_diff=Func(F('rating') - rating, function='ABS')).order_by('abs_diff').first()

答案 1 :(得分:2)

你可以获得两个Puzzle对象并在Python中进行比较:

# Note, be sure to check that puzzle_lower and puzzle_higher are not None
puzzle_lower = Puzzle.objects.filter(rating__lte=user_rating).order_by('-rating').first()
puzzle_higher = Puzzle.objects.filter(rating__gte=user_rating).order_by('rating').first()

# Note that in a tie, this chooses the lower rated puzzle
if (puzzle_higher.rating - user_rating) < abs(puzzle_lower.rating - user_rating):
    puzzle = puzzle_higher
else:
    puzzle = puzzle_lower