Django:更新查询集中对象的订单属性

7

我在我的模型上有一个属性,允许用户对对象进行排序。我必须根据包含新顺序中对象ID的列表更新元素的顺序;现在我正在遍历整个查询集并逐个设置对象。如何用整个查询集执行相同操作的最简单/最快方法是什么?

def update_ordering(model, order):
    """ order is in the form [id,id,id,id] for example: [8,4,5,1,3] """
    id_to_order = dict((order[i], i) for i in range(len(order)))
    for x in model.objects.all():
        x.order = id_to_order[x.id]
        x.save()
2个回答

6
这无法在一个单一的查询集操作中完成。据我所知,甚至不能使用原始SQL在一个查询中完成。因此,您将始终需要为每个要更新的对象调用更新调用。因此,您和Collin Anderson的解决方案对于您的描述似乎都是最佳的。
但是,您的用例是什么?整个列表每次都会更改吗?在大多数情况下,这似乎非常不可能。我可以看到一些不同的方法。
您像您所说保存订单字段,但是为订单列表生成差异:def
update_ordering(model, order):
    """ order is in the form [id,id,id,id] for example: [8,4,5,1,3] """
    original_order = model.objects.value_list('id', flat=True).order_by('order')
    order = filter( lambda x: x[1]!=x[2], zip(xrange(len(order)), order, original_order))
    for i in order:
        model.objects.filter(id=i[1]).update(order=i[0])

另一种方法,取决于你正在制作什么,是进行部分更新(例如使用AJAX),如果可能的话,而不是更新整个重新排序的集合,只需单独更新每个更新。这通常会增加总负载,但会更平均地分散在时间上。例如,将第五个元素逐步移动到第二个位置,这将引入3次交换:(5,4); (4,3); (3,2)。结果需要6次更新,而采用全局更新方法只需要4次更新。但小的操作会分散在时间上。

2

我不知道是否可以使用一个查询来完成这个任务,但无论如何这种方法都更加高效:

def update_ordering(model, order):
    """ order is in the form [id,id,id,id] for example: [8,4,5,1,3] """
    for id in model.objects.values_list('id', flat=True):
        model.objects.filter(id=id).update(order=order.index(id))

猜测只需一次访问数据库即可获取所有项目(所有项目都必须更新,因此您的解决方案也需要迭代所有项目)。 - Bernhard Vallant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接