2010-06-15 76 views
5

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

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() 

回答

4

这不能在一个单一的查询集操作来完成。据我所知,甚至无法用原始SQL在一个查询中完成。所以你总是需要更新每个需要更新的对象的调用。因此,您和科林安德森的解决方案似乎都非常适合您的描述。

但是,您的用例是什么?每一次真的整个列表都会改变吗?在大多数情况下,这似乎不太可能。我可以看到一些不同的方法。

您保存订单场像你说的,但是你生成的顺序列表中的DIFF: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]) 

另一种方法,这取决于你正在做什么是做部分更新(例如,使用如果可能的话,而不是更新整个重新排序的集合,只需单独更新每个更新。这通常会增加总负载,但会随着时间的推移而扩展。举例来说,将第5个元素逐步移动到2,这将引入3个交换:(5,4); (4,3); (3,2)。导致6次更新,而采用一次性方法只需要4次更新。但是小型业务将随着时间的推移而分散。

1

我不知道是否有可能做到这一点使用一个查询,但是这是在任何情况下更有效:

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)) 
+0

猜测它只保存一次就可以获取所有项目(所有项目都必须更新,因此您的解决方案也会遍历所有项目)。 – 2010-06-24 01:11:50