我有一个由(id,rank)对组成的词典。我想对id执行Django查询,以便生成的查询集按rank(降序)排序。
获取查询集非常简单:
rankings = {...}
result = MyModel.objects.filter(id__in=rankings.keys())
似乎答案应该包含某些注释,我可以将其用作order_by的一部分,但我无法弄清楚如何到达那里。
编辑:我忽略了提到我需要将结果作为QuerySet,因为这是tastypie API管道的一部分。
答案 0 :(得分:2)
这样的东西?
rankings = { 1 : 2, 2: 1, ... } # i.e. { 'id' : 'ranking', ... }
objects = list(MyModel.objects.filter(id__in=rankings.keys()))
objects.sort(key=lambda obj: rankings[obj.id])
答案 1 :(得分:0)
我能想出解决这个问题的唯一方法是创建一个与主要模型相关的新排名模型。在每个查询中,我将排名项插入到该模型中,然后能够通过关系执行order_by。 (使用注释将等级添加到学校记录中。)
class UserSchoolRanking(models.Model):
user = models.ForeignKey(User)
school = models.ForeignKey(School)
rank = models.IntegerField()
bulk_user_school_rank = [UserSchoolRank(user=user, school_id=k, rank=v)
for k, v in rankings.iteritems()]
UserSchoolRank.objects.bulk_create(bulk_user_school_rank)
schools = School.objects.filter(userschoolrank__user=user)\
.annotate(rank=Min('userschoolrank__rank'))\
.order_by('-userschoolrank__rank')
答案 2 :(得分:0)
我对Django> 1.10和PostgreSQL> 9.5的解决方案
from django.db.models import Func, Value, IntegerField, CharField
from django.contrib.postgres.fields import ArrayField
class ArrayPosition(Func):
function = 'array_position'
def __init__(self, items, *expressions, **extra):
if isinstance(items[0], int):
base_field = IntegerField()
else:
base_field = CharField(max_length=max(len(i) for i in items))
first_arg = Value(list(items), output_field=ArrayField(base_field))
expressions = (first_arg, ) + expressions
super().__init__(*expressions, **extra)
pk_list = [234,12,23]
queryset = SomeModel.objects.filter(pk__in=pk_list, ...)\
.annotate(ordering=ArrayPosition(pk_list, F('pk'), output_field=IntegerField()))\
.order_by('ordering')